github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/docs/translations/zh_CN/syscall_descriptions_syntax.md (about) 1 > [!WARNING] 2 > 3 > **请注意,这是社区驱动的官方 syzkaller 文档翻译。当前文档的最新版本(英文版)可在 [docs/syscall_descriptions_syntax.md](/docs/syscall_descriptions_syntax.md) 中找到。** 4 5 # Syscall description language 6 又称作 `syzlang` (`[siːzˈlæŋg]`) 7 8 系统调用描述的伪形式语法: 9 10 ``` 11 syscallname "(" [arg ["," arg]*] ")" [type] ["(" attribute* ")"] 12 arg = argname type 13 argname = identifier 14 type = typename [ "[" type-options "]" ] 15 typename = "const" | "intN" | "intptr" | "flags" | "array" | "ptr" | 16 "string" | "strconst" | "filename" | "glob" | "len" | 17 "bytesize" | "bytesizeN" | "bitsize" | "vma" | "proc" | 18 "compressed_image" 19 type-options = [type-opt ["," type-opt]] 20 ``` 21 22 常见的类型选项(type-options)包括: 23 24 ``` 25 "opt" - 该参数是可选的(如 mmap fd 参数,或 accept peer 参数) 26 ``` 27 28 其余的类型选项是类型特定的: 29 30 > 注:为了便于理解,每个类型选项下方都附带了从 syzlang 中挑选的相关示例,类型选项由"[]"包裹。 31 32 ``` 33 "const": 整型常量,类型选项: 34 值,基础类型("intN" 或 "intptr") 35 示例:const[0, int32] 或 ioctl$I2C_TIMEOUT(..., cmd const[I2C_TIMEOUT], ...),其中 I2C_TIMEOUT 为 dev_i2c.txt.const 定义的常量 36 "intN"/"intptr": 没有特定含义的整数,类型选项: 37 一个可选值范围(例如 "5:10" 或 "100:200") 38 或者一个标志描述的引用(见下文), 39 或单个值 40 如果使用范围,其后可选择性地跟对齐参数 41 示例:int8[100:200] 或 ioctl$UI_SET_KEYBIT(..., arg intptr[0:KEY_MAX]) 42 "flags": 一组值,类型选项: 43 标志描述的引用(见下文),基本的整型类型(例如 "int32") 44 示例:flags[iocb_flags, int32],其中 iocb_flags = IOCB_FLAG_RESFD, IOCB_FLAG_IOPRIO 45 "array": 可变/固定长度数组,类型选项: 46 元素类型,可选尺寸(固定为 "5",或范围限定为 "5:10"的闭区间) 47 示例:array[int8, 5] 或 array[int8, 5:10] 48 "ptr"/"ptr64": 指向对象的指针,类型选项: 49 方向(输入/输出/输入输出);对象的类型 50 ptr64 的大小为 8 字节,与目标指针大小无关 51 示例:io_getevents(..., timeout ptr[in, timespec, opt]),其中 opt 表示该参数是可选的 52 "string": 以零结尾的内存缓冲区(不包含指针间接寻址),类型选项: 53 一个常量字符串的引号中的字符串值(例如,"foo" 或 十六进制的`deadbeef`), 54 或一个对字符串标志的引用(特殊值 `filename` 将产生文件名),后面可跟着一个缓冲区大小(字符串值将用 \x00 填充到该大小) 55 示例:mount$9p_tcp(src ptr[in, string["127.0.0.1"]], ...) 56 "stringnoz": 非零终止的内存缓冲区(不包含指针间接寻址),类型选项: 57 一个常量字符串的引号中的字符串值(例如,"foo" 或 十六进制的`deadbeef`), 58 或一个对字符串标志的引用 59 示例:stringnoz[cgroup_subsystems],其中 cgroup_subsystems = "cpu", "memory", "io", ... 60 "glob": 要在目标文件上匹配的 glob 模式,类型选项: 61 一个引号中的模式字符串(语法参考:https://golang.org/pkg/path/filepath/#Match,例如,"/sys/" 或 "/sys/**/*") 62 也可以指定排除的 glob(例如 "/sys/**/*:-/sys/power/state") 63 示例:openat$sysfs(..., dir ptr[in, glob["/sys/**/*:-/sys/power/state"]], ...) 64 "fmt": 整数的字符串表示形式(非零终止),类型选项: 65 格式("dec"、"hex"、"oct" 之一)和值(resource、int、flags、const 或 proc) 66 其结果数据总是大小固定的(分别对应地格式化为 "%020llu", "0x%016llx" 或 "%023llo") 67 示例:fmt[hex, int32] 或 fmt[dec, proc[10, 20]] 68 "len": 另一个字段的长度(对于数组,它是元素的数量),类型选项: 69 对象的参数名称(argname) 70 示例:mmap$xdp(addr vma, len len[addr], ...) 或 read(..., buf buffer[out], count len[buf]) 71 "bytesize": 类似于 "len",但总是以字节为单位表示大小,类型选项: 72 对象的参数名称(argname) 73 示例:getsockopt$XDP_STATISTICS(..., val ..., len ptr[in, bytesize[val, int32]]) 74 "bitsize": 类似于 "len",但总是以位为单位表示大小,类型选项: 75 对象的参数名称(argname) 76 示例:bitsize[key, int16],其中 key 为 array[int8] 77 "offsetof": 字段与父类结构体头部的偏移量,类型选项: 78 字段(field) 79 示例:offsetof[ebt_among_info:FIELD, int32],其中 FILELD 为 ebt_among_info 的某个结构体成员(通过 : 的成员索引支持嵌套,如 offsetof[A:B:C, int32]) 80 "vma"/"vma64": 指向一组页面的指针(用作 mmap/munmap/mremap/madvice 的输入),类型选项: 81 可选的页面数量(例如 vma[7])或页面范围(例如 vma[2-4]) 82 vma64 的大小为 8 字节,与目标指针大小无关 83 示例:mmap$KVM_VCPU(addr vma, ...) 或 syz_kvm_setup_cpu$x86(..., usermem vma[24], ...) 84 "proc": 每个进程的int值(参阅下面的描述),类型选项: 85 值范围的起始,每个进程有多少个值,基础类型 86 示例:proc[0x0, 4, int8] 87 "compressed_image": zlib 压缩的磁盘映像 88 接受 `compressed_image` 作为参数的系统调用必须被标记为 `no_generate` 和 `no_minimize` 调用属性。 89 示例:syz_mount_image$f2fs(..., img ptr[in, compressed_image]) fd_dir (timeout[4000], no_generate, no_minimize) 90 "text": 指定类型的机器码,类型选项: 91 文本类型 (x86_real, x86_16, x86_32, x86_64, arm64) 92 示例:ptr[in, text[x86_64]] 93 "void": 静态大小为 0 的类型 94 主要用于模板和 varlen 联合体内部,不能作为系统调用的参数 95 示例:write$FUSE_INTERRUPT(..., arg ptr[in, fuse_out[void]], ...) 96 ``` 97 98 在 structs/unions/pointers 中使用时,flags/len/flags 也有尾随的基础类型的类型选项。 99 100 标志描述为: 101 102 ``` 103 flagname = const ["," const]* 104 ``` 105 106 或者对于字符串标志: 107 108 ``` 109 flagname = "\"" literal "\"" ["," "\"" literal "\""]* 110 ``` 111 112 调用属性如下所示: 113 114 ``` 115 "disabled": 该调用将不会被用于模糊测试;用于临时禁用某些调用或禁止特定参数组合。 116 "timeout[N]": 对该调用在默认值的基础上的额外执行超时(以毫秒为单位)。 117 "prog_timeout[N]": 对包含该调用的整个程序的额外执行超时(以毫秒为单位);如果程序包含多个这样的调用,则使用其最大值。 118 "ignore_return": 在回退反馈中忽略该系统调用的返回值;用于不返回固定错误代码而返回其他内容(如当前时间)的调用。 119 "breaks_returns": 在回退反馈中忽略程序中所有后续调用的返回值(不可信)。 120 "no_generate": 不要尝试生成该系统调用,即只使用种子描述来生成它。 121 "no_minimize": 在试图最小化崩溃程序时,请勿修改该系统调用的实例。 122 ``` 123 124 ## Ints 125 126 `int8`,`int16`,`int32` 和 `int64` 表示相应大小的整数。 127 `intptr` 表示指针大小的整数,即 C 的 `long` 类型。(译者注:intptr 不是指针,而是相当于 C 的 `size_t`) 128 129 通过追加 `be` 后缀(例如 `int16be`),整数就变成了大端序。 130 131 可以为整数指定一个数值范围,格式为 `int32[0:100]` 或 `int32[0:4096, 512]`(对于 512 对齐的 int)(译者注:int32[0:4096, 512] 意为其取值为{0,512,1024,...})。 132 133 整数的第一个类型选项也可以是对标志说明或数值的引用。在这种情况下,不支持对齐参数。 134 135 使用 `int64:N` 表示大小为 N 的位域。 136 137 可以将这些不同类型的 ints 作为 `const`、`flags`、`len` 和 `proc` 的基类型。 138 139 ``` 140 example_struct { 141 f0 int8 # 随机 1 字节整数 142 f1 const[0x42, int16be] # 2 字节整数常量,值为 0x4200(大端序 0x42) 143 f2 int32[0:100] # 随机 4 字节整数,取值范围为 0 至 100(含 100) 144 f3 int32[1:10, 2] # 值为 {1、3、5、7、9} 的随机 4 字节整数 145 f4 int64:20 # 随机 20 位域 146 f5 int8[10] # 1 字节整数常量,值为 10 147 f6 int32[flagname] # flagname 所引用的值集中的随机 4 字节整数 148 } 149 ``` 150 151 ## Structs 152 153 结构体描述为: 154 155 ``` 156 structname "{" "\n" 157 (fieldname type ("(" fieldattribute* ")")? (if[expression])? "\n")+ 158 "}" ("[" attribute* "]")? 159 ``` 160 > 注:"?"表示匹配前面的子表达式零次或一次,"+"表示匹配前面的子表达式一次或多次 161 162 字段可以在字段后的括号中指定属性,与字段类型无关。`in/out/inout` 属性指定每个字段的方向,例如: 163 164 ``` 165 foo { 166 field0 const[1, int32] (in) 167 field1 int32 (inout) 168 field2 fd (out) 169 } 170 ``` 171 172 你可以指定决定是否包含某个字段的条件: 173 174 ``` 175 foo { 176 field0 int32 177 field1 int32 (if[value[field0] == 0x1]) 178 } 179 ``` 180 181 参阅 [相应章节](syscall_descriptions_syntax.md#conditional-fields) 了解更多详情。 182 183 `out_overlay` 属性允许为结构体设置独立的输入和输出布局。在 `out_overlay` 字段之前的字段为输入字段,从 `out_overlay` 开始的字段为输出字段。输入字段和输出字段在内存中重叠(都从内存中结构体的起始位置开始)。例如: 184 185 ``` 186 foo { 187 in0 const[1, int32] 188 in1 flags[bar, int8] 189 in2 ptr[in, string] 190 out0 fd (out_overlay) 191 out1 int32 192 } 193 ``` 194 195 结构体后面的方括号中可以指定属性。属性包括: 196 197 - `packed`: 结构体的字段之间没有填充,对齐方式为 1;这类似于 GNU C 的 `__attribute__((packed))`;结构体的对齐方式可以用 `align` 属性覆盖 198 - `align[N]`: 结构体的对齐方式为 N,填充为 `N` 的倍数;填充内容未指定(但通常为零);类似于 GNU C 的`__attribute__((aligned(N)))`。 199 - `size[N]`: 结构体被填充到指定的大小 `N`;填充内容未指定(但通常为零) 200 201 ## Unions 202 203 联合体被描述为: 204 205 ``` 206 unionname "[" "\n" 207 (fieldname type (if[expression])? "\n")+ 208 "]" ("[" attribute* "]")? 209 ``` 210 211 在模糊测试过程中,syzkaller 会随机从联合体中选择一个选项。 212 213 你还可以指定一些条件,根据其他字段的值来决定相应的选项是否被选中的条件。参见 [相应章节](syscall_descriptions_syntax.md#conditional-fields) 了解更多详情。 214 215 联合体后的方括号中可以指定属性。属性包括: 216 217 - `varlen`: 联合体大小是所选特定选项的大小(非静态已知);如果没有该属性,联合体的大小是所有字段中的最大值(类似于 C 联合体)。 218 - `size[N]`: 联合体的填充大小为指定的 `N`;填充内容未指定(但通常为零) 219 220 ## Resources 221 222 资源代表需要从一个系统调用的输出传递到另一个系统调用的输入的值。例如,`close` 系统调用需要先前由 `open` 或 `pipe` 系统调用返回的值作为输入(fd)。为此,`fd` 被声明为一种资源。这是模拟系统调用之间依赖关系的一种方式,因为将一个系统调用定义为资源的生产者,而将另一个系统调用定义为消费者,就定义了它们之间一种宽松的调用顺序。资源被描述为: 223 224 ``` 225 "resource" identifier "[" underlying_type "]" [ ":" const ("," const)* ] 226 ``` 227 228 `underlying_type` 是 `int8`、`int16`、`int32`、`int64`、`intptr` 或其他资源(继承模型,例如,socket 是 fd 的子类型)之一。常量的可选集代表资源的特殊值,例如,`0xffffffffffffffffff`(-1)表示 “无 fd”,`AT_FDCWD`表示 “当前目录”。特殊值偶尔会作为资源值使用。如果没有指定特殊值,则使用特殊值 `0`。资源可以用作类型,例如: 229 230 ``` 231 resource fd[int32]: 0xffffffffffffffff, AT_FDCWD, 1000000 232 resource sock[fd] 233 resource sock_unix[sock] 234 235 socket(...) sock 236 accept(fd sock, ...) sock 237 listen(fd sock, backlog int32) 238 ``` 239 240 资源不一定要由系统调用返回。它们可以像其他数据类型一样使用。例如: 241 242 ``` 243 resource my_resource[int32] 244 245 request_producer(..., arg ptr[out, my_resource]) 246 request_consumer(..., arg ptr[inout, test_struct]) 247 248 test_struct { 249 ... 250 attr my_resource 251 } 252 ``` 253 254 对于更复杂的生产者/消费者场景,可以使用字段属性。例如: 255 256 ``` 257 resource my_resource_1[int32] 258 resource my_resource_2[int32] 259 260 request_produce1_consume2(..., arg ptr[inout, test_struct]) 261 262 test_struct { 263 ... 264 field0 my_resource_1 (out) 265 field1 my_resource_2 (in) 266 } 267 ``` 268 269 每种资源类型(联合体和可选指针除外)必须被至少一个系统调用 “生产”(用作输出),并被至少一个系统调用 “消费”(用作输入)。 270 271 ## Type Aliases 272 273 对于经常重复的复杂类型,可以使用以下语法给出简短的类型别名: 274 275 ``` 276 type identifier underlying_type 277 ``` 278 279 例如: 280 281 ``` 282 type signalno int32[0:65] 283 type net_port proc[20000, 4, int16be] 284 ``` 285 286 这样,在任何情况下都可以使用类型别名来代替基础类型。基础类型需要像结构体字段一样进行描述,即带有基础类型(如果需要的话)。此外,类型别名也可以用作系统调用参数。基础类型目前仅限于整数类型、`ptr`、`ptr64`、`const`、`flags` 和 `proc` 类型。 287 288 以下是一些内置的类型别名: 289 ``` 290 type bool8 int8[0:1] 291 type bool16 int16[0:1] 292 type bool32 int32[0:1] 293 type bool64 int64[0:1] 294 type boolptr intptr[0:1] 295 296 type fileoff[BASE] BASE 297 298 type filename string[filename] 299 300 type buffer[DIR] ptr[DIR, array[int8]] 301 ``` 302 303 ## Type Templates 304 305 类型模板的声明方式如下: 306 ``` 307 type buffer[DIR] ptr[DIR, array[int8]] 308 type fileoff[BASE] BASE 309 type nlattr[TYPE, PAYLOAD] { 310 nla_len len[parent, int16] 311 nla_type const[TYPE, int16] 312 payload PAYLOAD 313 } [align_4] 314 ``` 315 316 随后按如下方式使用: 317 ``` 318 syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]]) 319 ``` 320 321 内置类型模板 `optional` 定义如下: 322 ``` 323 type optional[T] [ 324 val T 325 void void 326 ] [varlen] 327 ``` 328 329 ## Length 330 331 你可以使用 `len`、`bytesize` 和`bitsize` 类型指定结构体或命名参数中特定字段的长度,例如: 332 333 ``` 334 write(fd fd, buf ptr[in, array[int8]], count len[buf]) 335 336 sock_fprog { 337 len len[filter, int16] 338 filter ptr[in, array[sock_filter]] 339 } 340 ``` 341 342 如果 `len` 的参数是指针,则使用被指向参数的长度。 343 344 用 `bytesizeN` 表示字段的 N 字节长度,N 的可能值为 1、2、4 和 8。 345 346 要表示父结构体的长度,可以使用 `len[parent, int8]`。当结构体相互嵌入时,要表示上一级父结构体的长度,可以指定特定父结构体的类型名称: 347 348 ``` 349 s1 { 350 f0 len[s2] # length of s2 351 } 352 353 s2 { 354 f0 s1 355 f1 array[int32] 356 f2 len[parent, int32] 357 } 358 ``` 359 360 `len` 参数也可以是一个路径表达式,它允许更复杂的寻址。路径表达式类似于 C 语言的字段引用,但也允许引用父元素和同级元素。在路径开头使用特殊引用 `syscall` 可以直接引用 syscall 参数。例如: 361 362 ``` 363 s1 { 364 a ptr[in, s2] 365 b ptr[in, s3] 366 c array[int8] 367 } 368 369 s2 { 370 d array[int8] 371 } 372 373 s3 { 374 # 这里指的是父结构体 s1 中的数组 c。 375 e len[s1:c, int32] 376 # 这里指的是同级结构体 s2 中的数组 d。 377 f len[s1:a:d, int32] 378 # 这里指的是子结构体 s4 中的数组 k。 379 g len[i:j, int32] 380 # 这里指的是系统调用参数 l。 381 h len[syscall:l, int32] 382 i ptr[in, s4] 383 } 384 385 s4 { 386 j array[int8] 387 } 388 389 foo(k ptr[in, s1], l ptr[in, array[int8]]) 390 ``` 391 392 ## Proc 393 394 `proc` 类型可用于表示每个进程的整数。这样设计的目的是为每个执行器设置独立的数值范围,使它们互不干扰。 395 396 最简单的例子就是端口号。`proc[20000, 4, int16be]` 类型意味着我们要生成一个从 `20000` 开始的 `int16be` 整数,并为每个进程分配 `4` 个值。因此,执行器中的数 `n` 的取值范围为 `[20000 + n * 4, 20000 + (n + 1) * 4)`。 397 398 ## Integer Constants 399 400 整数常量可指定为十进制字面量、`0x` 前缀的十六进制字面量、`'` 包围的字符字面量或从内核头文件中提取或由 `define` 指令定义的符号常量。例如: 401 402 ``` 403 foo(a const[10], b const[-10]) 404 foo(a const[0xabcd]) 405 foo(a int8['a':'z']) 406 foo(a const[PATH_MAX]) 407 foo(a int32[PATH_MAX]) 408 foo(a ptr[in, array[int8, MY_PATH_MAX]]) 409 define MY_PATH_MAX PATH_MAX + 2 410 ``` 411 412 ## Conditional fields 413 414 ### In structures 415 416 在 syzlang 中,可以为每个结构字段指定一个条件,以决定是否包含该字段: 417 418 ``` 419 header_fields { 420 magic const[0xabcd, int16] 421 haveInteger int8 422 } [packed] 423 424 packet { 425 header header_fields 426 integer int64 (if[value[header:haveInteger] == 0x1]) 427 body array[int8] 428 } [packed] 429 430 some_call(a ptr[in, packet]) 431 ``` 432 433 在本例中,只有当 `header.haveInteger == 1` 时,`packet` 结构才会包含 `integer` 字段。在内存中,`packet` 的布局如下: 434 435 | header_files.magic = 0xabcd | header_files.haveInteger = 0x1 | integer | body | 436 | - | - | - | - | 437 438 439 这相当于以下程序: 440 ``` 441 some_call(&AUTO={{AUTO, 0x1}, @value=0xabcd, []}) 442 ``` 443 444 如果 `header.haveInteger` 不是 `1`,syzkaller 会假装字段 `integer` 不存在。 445 ``` 446 some_call(&AUTO={{AUTO, 0x0}, @void, []}) 447 ``` 448 449 | header_files.magic = 0xabcd | header_files.haveInteger = 0x0 | body | 450 | - | - | - | 451 452 每个条件字段的长度都被假设为可变的,以及该字段所属的结构的长度也是可变的。 453 454 当一个变长字段出现在结构体中间时,结构体必须用 `[packed]` 标记。 455 456 禁止在位域上设置条件: 457 ``` 458 struct { 459 f0 int 460 f1 int:3 (if[value[f0] == 0x1]) # It will not compile. 461 } 462 ``` 463 464 但你可以在条件中引用位域: 465 ``` 466 struct { 467 f0 int:1 468 f1 int:7 469 f2 int (if[value[f0] == value[f1]]) 470 } [packed] 471 ``` 472 473 ### In unions 474 475 让我们来看看下面这个例子。 476 477 ``` 478 struct { 479 type int 480 body alternatives 481 } 482 483 alternatives [ 484 int int64 (if[value[struct:type] == 0x1]) 485 arr array[int64, 5] (if[value[struct:type] == 0x2]) 486 default int32 487 ] [varlen] 488 489 some_call(a ptr[in, struct]) 490 ``` 491 492 在这种情况下,将根据 `type` 字段的值选择联合体选项。例如,如果 `type` 是 `0x1`,那么 `alternatives` 类型可以是 `int` 或 `default`: 493 ``` 494 some_call(&AUTO={0x1, @int=0x123}) 495 some_call(&AUTO={0x1, @default=0x123}) 496 ``` 497 498 如果 `type` 是 `0x2`,则 `alternatives` 类型可以是 `arr` 或 `default`。 499 500 如果 `type` 既不是 `0x1` 也不是 `0x2`,syzkaller 只能选择 `default` 作为 `alternatives` 类型: 501 ``` 502 some_call(&AUTO={0x0, @default=0xabcd}) 503 ``` 504 505 为确保总是可以构建联合体,最后一个联合字段**必须总是没有条件的**。 506 507 因此,下面的定义将无法编译: 508 509 ``` 510 alternatives [ 511 int int64 (if[value[struct:type] == 0x1]) 512 arr array[int64, 5] (if[value[struct:type] == 0x1]) 513 ] [varlen] 514 ``` 515 516 在变异和生成程序的过程中,syzkaller 会随机选择一个满足条件的联合字段。 517 518 519 ### Expression syntax 520 521 目前,只支持 `==`、`!=` 和 `&` 操作符。不过,该功能被设计得可以便捷地添加更多运算符。如有需要,请随时提交 GitHub issue 或给我们发邮件。 522 523 表达式以 `int64` 值求值。如果一个表达式的最终结果不是 0,则假定该表达式被满足。 524 525 如果要引用字段的值,可以通过 `value[path:to:field]`,这与 `len[]` 参数类似。 526 527 ``` 528 sub_struct { 529 f0 int 530 # 引用父结构中的一个字段。 531 f1 int (if[value[struct:f2]]) # 与 if[value[struct:f2] != 0] 相同。 532 } 533 534 struct { 535 f2 int 536 f3 sub_struct 537 f4 int (if[value[f2] == 0x2]) # 引用一个同级字段。 538 f5 int (if[value[f3:f0] == 0x1]) # 引用一个嵌套字段。 539 } [packed] 540 541 call(a ptr[in, struct]) 542 ``` 543 544 被引用的字段必须是整型,且其引用路径中不能有条件字段。 545 条件字段。例如,以下描述将无法编译。 546 547 ``` 548 struct { 549 f0 int 550 f1 int (if[value[f0] == 0x1]) 551 f2 int (if[value[f1] == 0x1]) 552 } 553 ``` 554 555 你也可以在表达式中引用常量: 556 ``` 557 struct { 558 f0 int 559 f1 int 560 f2 int (if[value[f0] & SOME_CONST == OTHER_CONST]) 561 } 562 ``` 563 564 ## Meta 565 566 描述文件还可以包含 `meta` 指令,用于指定整个文件的元信息。 567 568 ``` 569 meta noextract 570 ``` 571 告诉 `make extract` 不提取此文件的常量。尽管如此,仍可在此文件上手动调用 `syz-extract` 。 572 573 ``` 574 meta arches["arch1", "arch2"] 575 ``` 576 将此文件限制在给定的体系结构中。在其他架构上,`make extract` 和 `make generate` 不会使用该文件。 577 578 ## Misc 579 580 描述文件还包含指向 Linux 内核头文件的 `include` 指令、指向自定义 Linux 内核头文件目录的 `incdir` 指令和定义符号常量值的 `define` 指令。 581 582 syzkaller 执行器定义了一些[伪系统调用](/docs/pseudo_syscalls.md),可以像描述文件中的其他系统调用一样使用。这些伪系统调用可扩展为 C 代码,并可执行用户自定义的操作。你可以在 [executor/common_linux.h](/executor/common_linux.h) 中找到一些例子。 583 584 另请参阅 [tips](/docs/syscall_descriptions.md#tips),了解如何编写好的描述。