From be0441486d54ef572bce9fb9f3ee3f8f2c4b1536 Mon Sep 17 00:00:00 2001 From: Nick Zavaritsky Date: Fri, 3 May 2019 19:14:22 +0000 Subject: [PATCH] Compressed syscall database wtih O(1) lookup libkafel.so 5x smaller (x86_64, stripped): down to 88KiB from 440KiB. Closes #20 --- src/Makefile | 28 +- src/context.c | 1 - src/context.h | 2 +- src/kafel.c | 4 +- src/parser.y | 2 +- src/syscall.c | 78 ++---- src/syscall.h | 10 +- src/syscalldb.h | 115 ++++++++ src/syscalldb.inl | 84 ++++++ src/syscalldb_generator | Bin 0 -> 403264 bytes src/syscalls/Makefile | 43 +++ src/syscalls/syscalldb_generator.c | 423 +++++++++++++++++++++++++++++ 12 files changed, 711 insertions(+), 79 deletions(-) create mode 100644 src/syscalldb.h create mode 100644 src/syscalldb.inl create mode 100755 src/syscalldb_generator create mode 100644 src/syscalls/Makefile create mode 100644 src/syscalls/syscalldb_generator.c diff --git a/src/Makefile b/src/Makefile index 86f2809..1b2c72c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -17,18 +17,14 @@ # limitations under the License. # +SUBDIRS:=syscalls + OBJCOPY?=objcopy CFLAGS+=-fPIC -fvisibility=hidden -GENERATED_SRCS:=lexer.c parser.c +GENERATED_SRCS:=lexer.c parser.c syscalldb.c GENERATED:=lexer.h parser.h ${GENERATED_SRCS} -TEMPORARY:=libkafel_r.o libkafel.o -SYSCALL_LISTS:=amd64_syscalls.c \ - i386_syscalls.c \ - aarch64_syscalls.c \ - mipso32_syscalls.c \ - mips64_syscalls.c \ - arm_syscalls.c +TEMPORARY:=libkafel_r.o libkafel.o syscalldb.gperf SRCS:=kafel.c \ context.c \ codegen.c \ @@ -37,8 +33,7 @@ SRCS:=kafel.c \ policy.c \ range_rules.c \ syscall.c \ - ${GENERATED_SRCS} \ - $(SYSCALL_LISTS:%.c=syscalls/%.c) + ${GENERATED_SRCS} DYNAMIC_TARGET:=${PROJECT_ROOT}libkafel.so STATIC_TARGET:=${PROJECT_ROOT}libkafel.a TARGET=${DYNAMIC_TARGET} ${STATIC_TARGET} @@ -65,6 +60,10 @@ lexer.h lexer.c: lexer.l parser.h parser.c: parser.y bison $< +syscalldb.c: syscalls + ./syscalls/syscalldb_generator > ./syscalldb.gperf + gperf -m10 --output-file=./syscalldb.c ./syscalldb.gperf + # DO NOT DELETE THIS LINE -- make depend depends on it. kafel.o: codegen.h context.h includes.h policy.h expression.h syscall.h @@ -76,14 +75,9 @@ expression.o: expression.h common.h includes.o: includes.h common.h policy.o: policy.h expression.h common.h range_rules.o: range_rules.h policy.h expression.h common.h syscall.h -syscall.o: syscall.h common.h +syscall.o: syscall.h syscalldb.h common.h +syscalldb.o: syscall.h syscalldb.h syscalldb.inl lexer.o: parser.h context.h includes.h policy.h expression.h syscall.h lexer.o: common.h parser.o: parser.h context.h includes.h policy.h expression.h syscall.h parser.o: lexer.h -syscalls/amd64_syscalls.o: syscall.h -syscalls/i386_syscalls.o: syscall.h -syscalls/aarch64_syscalls.o: syscall.h -syscalls/mipso32_syscalls.o: syscall.h -syscalls/mips64_syscalls.o: syscall.h -syscalls/arm_syscalls.o: syscall.h diff --git a/src/context.c b/src/context.c index ec4acf3..5c4caf5 100644 --- a/src/context.c +++ b/src/context.c @@ -70,7 +70,6 @@ void kafel_ctxt_reset(kafel_ctxt_t ctxt) { } ctxt->default_action = 0; ctxt->lexical_error = false; - ctxt->syscalls = NULL; } void kafel_ctxt_clean(kafel_ctxt_t ctxt) { diff --git a/src/context.h b/src/context.h index f93d4b3..407aece 100644 --- a/src/context.h +++ b/src/context.h @@ -46,7 +46,7 @@ struct kafel_ctxt { struct policy* main_policy; int default_action; uint32_t target_arch; - const struct syscall_list* syscalls; + uint32_t target_arch_mask; struct { enum { INPUT_NONE, diff --git a/src/kafel.c b/src/kafel.c index 34c2a34..36660f2 100644 --- a/src/kafel.c +++ b/src/kafel.c @@ -57,8 +57,8 @@ static int parse(struct kafel_ctxt* ctxt) { kafel_yyset_column(1, scanner); kafel_yyset_lineno(1, scanner); - ctxt->syscalls = syscalls_lookup(ctxt->target_arch); - if (ctxt->syscalls == NULL) { + ctxt->target_arch_mask = syscall_get_arch_mask(ctxt->target_arch); + if (!ctxt->target_arch_mask) { append_error(ctxt, "Cannot resolve syscall list for architecture %#x\n", ctxt->target_arch); kafel_yylex_destroy(scanner); diff --git a/src/parser.y b/src/parser.y index 82e78ac..9123fab 100644 --- a/src/parser.y +++ b/src/parser.y @@ -298,7 +298,7 @@ syscall_id $$ = syscall_custom(value); } else { $$ = (struct syscall_descriptor*) - syscall_lookup(ctxt->syscalls, $1); + syscall_lookup(ctxt->target_arch_mask, $1); if ($$ == NULL) { emit_error(@1, "Undefined syscall `%s'", $1); free($1); $1 = NULL; diff --git a/src/syscall.c b/src/syscall.c index 6163643..71bf394 100644 --- a/src/syscall.c +++ b/src/syscall.c @@ -25,75 +25,57 @@ #include #include "common.h" +#include "syscalldb.h" // Fix for Linux <3.12 #ifndef EM_ARM #define EM_ARM 40 #endif -#define SYSCALL_LIST_DECL(arch) \ - extern const struct syscall_descriptor arch##_syscall_list[]; \ - extern const size_t arch##_syscall_list_size; - -#define SYSCALL_LIST(audit_arch, arch) \ - { audit_arch, arch##_syscall_list, &arch##_syscall_list_size } - -SYSCALL_LIST_DECL(arm) -SYSCALL_LIST_DECL(aarch64) -SYSCALL_LIST_DECL(amd64) -SYSCALL_LIST_DECL(mipso32) -SYSCALL_LIST_DECL(mips64) -SYSCALL_LIST_DECL(i386) +struct syscall_descriptor* syscall_custom(uint32_t nr) { + struct syscall_descriptor* rv = calloc(1, sizeof(*rv)); + rv->nr = nr; + return rv; +} -const struct syscall_list syscall_lists[] = { +uint32_t syscall_get_arch_mask(uint32_t arch) { + switch (arch) { + default: + return 0; #ifdef AUDIT_ARCH_ARM - SYSCALL_LIST(AUDIT_ARCH_ARM, arm), + case AUDIT_ARCH_ARM: + return SYSCALLDB_ARCH_ARM_FLAG; #endif #ifdef AUDIT_ARCH_AARCH64 - SYSCALL_LIST(AUDIT_ARCH_AARCH64, aarch64), + case AUDIT_ARCH_AARCH64: + return SYSCALLDB_ARCH_AARCH64_FLAG; #endif #ifdef AUDIT_ARCH_X86_64 - SYSCALL_LIST(AUDIT_ARCH_X86_64, amd64), + case AUDIT_ARCH_X86_64: + return SYSCALLDB_ARCH_X86_64_FLAG; #endif #ifdef AUDIT_ARCH_MIPS - SYSCALL_LIST(AUDIT_ARCH_MIPS, mipso32), + case AUDIT_ARCH_MIPS: + return SYSCALLDB_ARCH_MIPS_FLAG; #endif #ifdef AUDIT_ARCH_MIPS64 - SYSCALL_LIST(AUDIT_ARCH_MIPS64, mips64), + case AUDIT_ARCH_MIPS64: + return SYSCALLDB_ARCH_MIPS64_FLAG; #endif #ifdef AUDIT_ARCH_I386 - SYSCALL_LIST(AUDIT_ARCH_I386, i386), + case AUDIT_ARCH_I386: + return SYSCALLDB_ARCH_I386_FLAG; #endif -}; - -struct syscall_descriptor* syscall_custom(uint32_t nr) { - struct syscall_descriptor* rv = calloc(1, sizeof(*rv)); - rv->nr = nr; - rv->is_custom = true; - return rv; -} - -const struct syscall_list* syscalls_lookup(uint32_t arch) { - for (size_t i = 0; i < sizeof(syscall_lists) / sizeof(syscall_lists[0]); - ++i) { - if (syscall_lists[i].arch == arch) { - return &syscall_lists[i]; - } } - return NULL; } -const struct syscall_descriptor* syscall_lookup(const struct syscall_list* list, +const struct syscall_descriptor* syscall_lookup(uint32_t mask, const char* name) { - ASSERT(list != NULL); - ASSERT(name != NULL); - /* TODO use binary search if syscalls can be guaranteed to be - * sorted alphabetically - */ - for (size_t i = 0; i < *list->size; ++i) { - if (strcmp(name, list->syscalls[i].name) == 0) { - return &list->syscalls[i]; - } + const struct syscalldb_definition* def = syscalldb_lookup(name); + if (def && mask & def->arch_mask) { + struct syscall_descriptor* rv = calloc(1, sizeof(*rv)); + syscalldb_unpack(def, mask, rv); + return rv; } return NULL; } @@ -102,8 +84,6 @@ void syscall_descriptor_destroy(struct syscall_descriptor** desc) { ASSERT(desc != NULL); ASSERT((*desc) != NULL); - if ((*desc)->is_custom) { - free(*desc); - } + free(*desc); (*desc) = NULL; } diff --git a/src/syscall.h b/src/syscall.h index c826474..90b81cf 100644 --- a/src/syscall.h +++ b/src/syscall.h @@ -40,15 +40,9 @@ struct syscall_descriptor { struct syscall_arg args[SYSCALL_MAX_ARGS]; }; -struct syscall_list { - uint32_t arch; - const struct syscall_descriptor* const syscalls; - const size_t* const size; -}; - struct syscall_descriptor* syscall_custom(uint32_t nr); -const struct syscall_list* syscalls_lookup(uint32_t arch); -const struct syscall_descriptor* syscall_lookup(const struct syscall_list* list, +uint32_t syscall_get_arch_mask(uint32_t arch); +const struct syscall_descriptor* syscall_lookup(uint32_t arch_mask, const char* name); void syscall_descriptor_destroy(struct syscall_descriptor** desc); diff --git a/src/syscalldb.h b/src/syscalldb.h new file mode 100644 index 0000000..b35613c --- /dev/null +++ b/src/syscalldb.h @@ -0,0 +1,115 @@ +/* + Kafel - syscall database + ----------------------------------------- + + Copyright 2019 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +#ifndef KAFEL_SYSCALLDB_H +#define KAFEL_SYSCALLDB_H + +#include +#include +#include + +struct syscalldb_definition; +struct syscall_descriptor; + +enum { + SYSCALLDB_ARCH_ARM_FLAG = 0x01, + SYSCALLDB_ARCH_AARCH64_FLAG = 0x02, + SYSCALLDB_ARCH_X86_64_FLAG = 0x04, + SYSCALLDB_ARCH_MIPS_FLAG = 0x08, + SYSCALLDB_ARCH_MIPS64_FLAG = 0x10, + SYSCALLDB_ARCH_I386_FLAG = 0x20, +}; + +const struct syscalldb_definition* syscalldb_lookup(const char* name); +const char* syscalldb_reverse_lookup(uint32_t arch_mask, uint32_t nr); + +void syscalldb_unpack(const struct syscalldb_definition* definition, + uint32_t arch_mask, struct syscall_descriptor* dest); + +/* + internals + + Generated from individual syscall lists, has O(1) lookups and takes + advantage of the redundancy in the data set to reduce footprint + dramatically. + + O(1) lookups are courtesy of the perfect hash function generated with + GNU gperf. PHF maps a name to an index in the table of + tuples. If names match, syscall definition is found at the given + offset. + + Syscall definitions are of the variable length and stored back to + back. For details, consult syscalldb_definition struct. + +*/ + +#define SYSCALLDB_MAX_ARGTYPE 8 +#define SYSCALLDB_MAX_ARGNAME 0xffff + +#define SYSCALLDB_ARGNO(no) (((uint32_t)(no)) << 24) +#define SYSCALLDB_ARGTYPE(type) (((uint32_t)(type)) << 16) +#define SYSCALLDB_ARGNAME(name) ((uint32_t)(name)) + +#define SYSCALLDB_GET_ARGNO(x) (((x)&UINT32_C(0xff000000)) >> 24) +#define SYSCALLDB_GET_ARGTYPE(x) (((x)&UINT32_C(0x00ff0000)) >> 16) +#define SYSCALLDB_GET_ARGNAME(x) (((x)&UINT32_C(0x0000ffff))) + +struct syscalldb_entry { + uint16_t name; + uint16_t definition_offset; +}; + +/* + Observations: + + (1) very few syscalls are arch-specific; + + (2) syscall numbers varies wildly across archs; + + (3) argument names and sizes (modulo pointer size differences) are the same + across archs with a few notable exceptions (ex: clone). + + Last but not least, avoid pointers in static data structures with + initializers! Due to PIC requirements every single one of theese + require relocation. Increases the footprint and has runtime overhead. + +*/ +struct syscalldb_definition { + uint32_t arch_mask; /* archs providing this syscall */ + uint32_t n_arg_info; /* if >INT32_MAX), consult ext_arg_info; + it has -n_arg_info entries */ + union { + uint32_t arg_info[1]; /* argno, argtype, argname */ + struct { + uint32_t arch_mask; /* archs this entry applies to */ + uint32_t arg_info; /* argno, argtype, argname */ + } ext_arg_info[1]; + }; + /* uint32_t nr[]; syscall numbers, one value per a bit set in arch_mask */ +}; + +#define SYSCALLDB_DEFINITION_NR(d) \ + (&(d)->arch_mask + 2 + \ + ((d)->n_arg_info > INT32_MAX ? 2 * -(d)->n_arg_info : (d)->n_arg_info)) + +#define SYSCALLDB_DEFINITION_NEXT(d) \ + (typeof(d))(SYSCALLDB_DEFINITION_NR(d) + __builtin_popcount((d)->arch_mask)) + +#endif /* KAFEL_SYSCALLDB_H */ diff --git a/src/syscalldb.inl b/src/syscalldb.inl new file mode 100644 index 0000000..70eefb9 --- /dev/null +++ b/src/syscalldb.inl @@ -0,0 +1,84 @@ +/* + Kafel - syscall database helper routines + ----------------------------------------- + + Copyright 2019 Google Inc. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +#include "syscall.h" + +/* O(1) */ +const struct syscalldb_definition* syscalldb_lookup(const char *name) { + const struct syscalldb_entry *entry; + if (!(entry = syscalldb_lookup_internal(name, strlen(name)))) return NULL; + return (const struct syscalldb_definition*)( + syscalldb_definitions+entry->definition_offset); +} + +static inline uint32_t get_nr( + const struct syscalldb_definition* def, uint32_t mask +) { + uint32_t match = mask & def->arch_mask; + return SYSCALLDB_DEFINITION_NR(def)[ + __builtin_popcount(def->arch_mask & (match^(match-1))) - 1]; +} + +/* O(n) */ +const char* syscalldb_reverse_lookup(uint32_t mask, uint32_t nr) { + const struct syscalldb_definition* def = (typeof(def))syscalldb_definitions; + for (; def->arch_mask; def=SYSCALLDB_DEFINITION_NEXT(def)) { + if (mask&def->arch_mask && get_nr(def, mask)==nr) { + uint32_t offset = (uint32_t)( + (const uint32_t*)def-syscalldb_definitions); + const struct syscalldb_entry* entry = syscalldb_entries; + while (entry->definition_offset!=offset) ++entry; + return syscalldb_name_pool+entry->name; + } + } + return NULL; +} + +void syscalldb_unpack( + const struct syscalldb_definition* def, uint32_t mask, + struct syscall_descriptor *dest) { + + memset(dest, 0, sizeof *dest); + dest->nr = get_nr(def, mask); + if (def->n_arg_info<=INT32_MAX) { + for (uint32_t i=def->n_arg_info; i--; ) { + int argno = SYSCALLDB_GET_ARGNO(def->arg_info[i]); + dest->args[argno].size = SYSCALLDB_GET_ARGTYPE(def->arg_info[i]); + dest->args[argno].name = syscalldb_arg_name_pool + +SYSCALLDB_GET_ARGNAME(def->arg_info[i]); + } + } else { + for (uint32_t i=-def->n_arg_info; i--; ) { + if (mask & def->ext_arg_info[i].arch_mask) { + int argno = SYSCALLDB_GET_ARGNO(def->ext_arg_info[i].arg_info); + dest->args[argno].size = + SYSCALLDB_GET_ARGTYPE(def->ext_arg_info[i].arg_info); + dest->args[argno].name = syscalldb_arg_name_pool + +SYSCALLDB_GET_ARGNAME(def->ext_arg_info[i].arg_info); + } + } + } + for (int i=0; i!=SYSCALL_MAX_ARGS; ++i) { + if (dest->args[i].name && !dest->args[i].size) { + dest->args[i].size = syscalldb_pointer_size[ + __builtin_ctz(mask&def->arch_mask)]; + } + } +} diff --git a/src/syscalldb_generator b/src/syscalldb_generator new file mode 100755 index 0000000000000000000000000000000000000000..f7b18d83b36333f4502ffe97072e2ab2b07dbf3c GIT binary patch literal 403264 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

&i!?b{6$fxm9t!( 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≤1g&ml^HtDRn>0B=pTU{}dmcFDHLv z@58*kZfg7cZUk>$puIHW`w`*kek*%4{)>+7f0+s1{Q>`!e^7X?KUQDPp99`$_~+{d z9zS2-ea6^v*wyI1|xHsAflZb+4A<)5EQf6#nG@ld`X`J?>vqW%1Zn3=nfk7YyRsr>V`)fdB4 z{`nj5FO=U#_{u*oI@LerpWhh&G#^tuJ-*6UF1(mO&R72VNzSMet^D(sqhI;wWq)eC zVrDA;{6@r6`R9e_@taBe5J-_`E3L7 z%<7MqSN{3!19-|mpI7}U|NIXEczO2+<)42jfam=owf%cMm4CiT059+Up#1aO1n|6n zWW`th`SacJD$&Y6zYWjt{{6YvSJv-I?j}F`Q_Lssw|wx6jL!Nzwita+famXvml)pj zMyH1TWy(Jp@b3-y>hJGl#QT8qy=k8w&lq0pdC&cC%6`G)V0>-%Z)E2cWL>Xlh`#&r zPwQE_AEiFux<5{D1KtAa&++npzHJ8HeF3~(;j6u9{1)x~GqhfycaevXQf~A z9-maYEqL|7t9JhRcHkAjt9Cxz&ftAQ{Z-q)Zs7eJylS79a2j~uucP)d5WHXGpMPKF z`^iTlul|tQKF^{2F#OZ|X0`v=e(qGf%fWj9JRe^s!54n2ewV)veV-9ef1ci!^~AjJ zZUS#B{PX(r@5N_j^miWRSE;?2KF@dW@kyl@q5nS>;`PcH-zUKP61?ZlzgLYOn-Om* z`u&&|dug>5cY&&daCL%fY)IyzZ zN579RwLMQDG(PM=e%3RH=Uh7vId3=j0&frSs(qe7TkuxWAF4f{SjPK@!|^Zn{=x5u zT5nSO_4%RK$C3DV2mW=0R(&52Eqy(V@A_hNFUrpf;Q8~Ozi*7`cmA2+Jq@1wUyN4%^1T9hdFL-zKJlx-Q$BI|7yJG^=8yB0PrSP`szf(nzfDi{ z`*`N-NiEsmBmYzTyYiPWAfAqwx0}lE{Q>=5`MqU--gwII{V{kxetG}X{8!^$sy)i@ z{WIcOX?}0{pIU#)?>z*()c1|4{wd$~nc#W89_8DXKgzc)Iu%d(w)=xuSNXPQfLB-f zwr>T`@9)ZQUEBD1yp?ZzW&qFIpYm-BKh+-P+wNCK^{0H>eFJ#Pw=I7>KB=_wZTAV_ zc|4VGTlmViEjos;e5oHYo+;mUrR8J#ov(b`o$$}s&wM|MmrtdYZ~F!OQ~qoDm-l(p z%748KysYQ9#r#!%=*x*`Y`^7YF9RQr?<_fR*aO0@FfUWb1^KT|$j`EwWfTSce(r~I^w=?|VCR{3eAKa?L< z{8(6&pLQ(%`FgqID?hFDr{XI=?bZ0_@$~s%*8SzmPdnZ4WPjfKy*=K_PpkZH?yvIG zYQC%dw4z;Kj8=Zy;r2a*^u_Q}+iQP)PljRY@51x;gB6z-jt^IGp z)B3Myw?9U=r2gs^NH88Nkdd$a#otGd=-S#JGv`43+W`NLgce?Bqf^IA$5;O32Vp3G zvhb8YS+ti=r8ndK*lz=PdG`n9Pi_dF-yc%#kI9eY{gqm$+w;#H{|fN_67VmU zf6Vp8=zlSu-5v6y!yl8dS4vCQ~u<< z@RW~w<2u4qKI%;Zcs_pVJQew?eAJ?2^{af;8wK$4j;HcbkH;|Oqn5qOM=e_Us6{LP zv}on07VZAtOMBS}hR^3+J}a$!)H@PS$5TFP*_(Afp?uU=f){!}C%jNTYVkFH6YcHo z3-vz&rTqqy&wIR9{_9J?Q~qn=xqVsdPx-I+M3K%f5nfjPUcL?aeUE|>%YW_VQ)%Vf z9!PtM;bo0)7ySD-hGw15#{5-&?*aIi)&3Zs@_T=YU~ThzSK7Xm-}^NDb3ElIkiJUu zdrMy5?}@&T`ui&2Un*WKp3j0;gMV62l0C8VseI)x?;pU+yZtDC`DPgE^IhdHm%qwi zE;`je%^K?xFPyS?mo>uW4eE`qx%StO>y3TX;{^#!_v_D$$Or5VPU;25p7su20u+s12YpTD> zm;PZOp327}yi|YO9_35_X#mgLrKd)kEl{)Ygb&Zkv-aeGtg#^4=S;rQwJvGLOFQU3Y<0sr*AIxqir#J|k~{k^H3 z*P0by`R>OB{PTEZrIqjgM*%$TFUl*PyAjXFBY3razv%JUobz=*fziay+x7De=J36g z{N3K(I*%k)9?I~DE|NqZ|_;}KaO_> zc*=k63;`QNx!ST2>+gTMwRHp@NfSr>36kP z;@?xws1kh){_R^O{jPQj{yhsLbiP1s$1le_0snNqf3@-M!oMLH;`{AcrPN@ z8(QtZztKN7I;P+Gr!k(*ts}gV*!ySjCYb#f8-0b*Zhwp(h<|s~5#BQJ9sw_OK7{Hs zW`B%7mH3=U`}Fbb4vXJBqhtD=e?R5B!tnm~Xh!{xw-|jthvELYd{%l1c%Gj@^_BPi z=q2#>p#FS5U+MW5vhRyX{I@1Q`d_mKs>1R+f_DP)I{!lU?rr(nD^wd4YlXfigA(~N zM$zA!=BqZSZ4UeMmLcK$UwnPg=ZC4!zw^Pn7`%h5zI?xquP+B32`~;t{}F-y;QnU) z{;Lakhl3X|E4RzNz#9x+*7-urutDG*8Hi^u=HKd%F?})qc<}y-;6!NYzuM?2M#uC! ze=6nM!0_?Y-v?xUUo{=Pe}FeDqy6rW({s@OISh~I1BSoQXx|^B^D|W+j`srP52L+Q zdw%@}c!ySqx7_@5`(yM<%72F7D$}>Y1LZe8q4>n~JAY&JeF4Mk&+DskM*Q=*AB_d? zA^TqBBKY#}a-%03J;&w~*BQSl_D-PwnwkB(7=5MLvxo8bG1}uf4F2ihjW_uVjlRU_ z)baKj%C`kCl>bce{H5W|H2O}X-M_({53(B!pYP`V{q{ZB^8|Rle<-$}!0nIG(`Y}9 zB6xb=nsxug1NiqIcs_r~d%koU=ksj>p3b{b`*=E1|FQTve*}2P(>_D_ScD%sZ%6!C z|9A`gcLLAvx9{cb-;>Ngmj~)E@BIZUu>XTP!n>9JFd00L=dWzMoo}?ypLVwI6}`Ru z3;+HFqk-ky_4O^E-@CpT-5C9ULon9=V)|nInZ&0Ff*w!pPgHx4#Vdxl8~(k6V9dYR z^H{9^J%WF~2hYcA-@g#EKgQn||Na-jw$O^-5k_}3I;P+GT`7MQAXJ_K(NGn}(rT^~L=CjPd$31pWP}k7vpUsP^La#qMW4_}=`{D&d`K-?QHey$yID z5?|T>nbH3I=l;dMC;tk4r_x^h`DkOy$Gd>}vFy3P>}h23zTa;<_!r<`tbKa@QLN&h z=HP9If33{E)UVq2MBi564L1EFjP~(#tnppH)8`|vd_f-1 z$)@iHqi;5Pw$YCF0Q{{3@r>ckF#R#S-y`275Kp%+EBzdJx1q?#v!!PL8%BG7UuJx_ zZw37Q@b7bz_xYMXzqq~_{U!SM1<%jJ-oW>CQh=T~_@PhSq+S>XBnJ#V}z z;QhFc@NNKa0(jm&xSZS1E#S>Yqu&qaz*l>`+vrq7USK}I3k6?>mi|=L@Up(2jm5Jc_xBAE^#14fAD@55^gDk(?X7)a{LCAFA$X&~ zd)C^!kI(L}+aIG}L4UKDU{3ryX`fr-pTD1e(4J2h8J%jz3`0~1HT`~ z=BG>1*SL=G-lYD9g15rji$7l+b_HvNYfeWcN@FGhEvd^h45!|P#qGdRyh z@$mCy9DgbM6MhY&+VA^M#@_kh`TWzz3*T?voAM3ZkpSHn`60y9@qGP%h{bcb(PNBu z*a`5jsuG^}r-|U54W5r*K7X2Q_D?n1{c-wc1fKGFsD8XZ^tbwS`(yN3ls9=1oHXZxEbrcpkr*#!t0p7Uj=kd`Zn$>Gs6@dl0<8Bk1kL*Hf36e=+^ee}(cF z;Gg4tWZ$d!{Wmr~JKlTXO%M3DGNV6^_c{7*f#K(QxO`T+;lt(edPW`LwE*vz;CcOJ z^~cM%0q@oTUI+NPKY006x(oU~4dCV7A9{m#eue!Zwf(#QL&3W#;9uVT;XLsECxGYu zBP;$C@NRa;t3=-f-bK`(pC9M-mGyh=2E4zWf2!WO z{CSz8uT|Ng8mo$==-@Ty&ZZSk*_;Z@7OZus{cc-21dupRz&uOqzE@b7r= zs@>lQf;SjE-@oMFhmJ(Pw&TG$ls}sBQ~TMZFZR78W>)-jIe6y;#_LHL{c%ICL*F4V z{P}NNdw<~NQ|X()>q9}WKR*v`Rz`p4QT`d>nZA3CPW8v-yU_oRGdzti!V~S~Q|U$6 z|AOJEeF{%>uZ;D13jWP8JozI$(ZUm*>faOi_dErkxB7b3=&>37>xX~08=mYJo@n8T zPW5jo_W#lFRA0gqovPpEN8sPFh9~=lC)&%W(r@D54=CvShi+u%uLSGWAFP@@y-J8oYaD~lphaXC(2Lfexdex zo6%X%i(No_*`D^Y$lBkP_P%(r@l)NLi~R#B=;t{;#{EkErs{Y3XRx<%Ko^;IPTxy<^BEbO6sQ{cs`%VdVlr$+X??RC7!;2H}8C4f1!PDk0GyF ze{=h?(to9WjYiS(#P*ho{}1$^62SX1XZ(%W4}T(f)!rYu1$aN8y*OU%yvWpe-cEnm zHML+Z4f-3`1!DDwG(-ygEB|C|Ee$+XYY zEq-Sj?Ref_V*U?AUqkRx_YcPOJAV(>cQ%JH%=~frtn?`K*TcVkY<=k>!@t((RQy{h zzaeg6GeFOASA!FUEfjeSHFW?%#)opK8xam9L}v zD=@#VAHdrOzQ)g3ykh(^!a*UU%@igVzf>ukpn32ciFD7{jZKHxB)m z;a}eE!~Gjb`>fCV9Ovgv4+ZZ#b%ZyOcpix(em=5)pPJQQ<;UI`MZVsn`$t~w^(y>3 zBhddG-}7sywl9_69K4wRtns`K{~pe&sKWBoz#CDad{(g;;GIG|eZ62de6^Rmj83h; z1(ZJoysY-e%0C3&C< zyFI>tVgJW)|`|#CsvcI<|Te4OhO4r*xz02zB`>|eB zy0%)+;9XZ=Z;pH^FVAW{UzD$p=X!JG+x05zUrs%#+3L69YHfwWem9rj(Caz;vR{{J ztrPEuJv$=58ngJf&V4x;{!YgK{J&qX9tx(F)fIG(-?Wl5#eW->e+nE+TF|^p=Ra=- zU-=rhf!0rb{%E&l`3rSm3VI*1HT;eF)xLyAzbs4YdP@wEU(0VO^OYA!__{Ai?#r*s z{uSf7`qF=)U%}C@zu~X8;1lS1@c#upO@YPEynecEUXF|F8%TYR>w$*{H_WS+;ZO5)A z_rGxegIn#_de8FZ3IOXD>J<)FgIP)$D;eXpgaP`}vP)vnjQ zzEMH#f8FaF7t}7+z22ap_O$NxO$uta>t5fqp!U7)_087w^L4K`EOetD*S)@Zq4|31 zvwmTV!hY+$zGXq<#=3eM6|QAGS@(M5!Y7PZ>t5fg(CvwD2fBWtNkQY#y7F5WH2$o6 zeVaAo=(^XpEv&C!)GusT&^WTLe6jb_{?@&|eWB5MuWMBNM!I|-`1I>6pD->%m4?RNgB;`ObHxEIq;<;7dY>y0-k z-gTK@Tsy9WS15c|yxx5EU+ey7%VI&b)wMZ2i#O`#g>Uzx7A5%&8Wl93(S7xZ;`Oc8 zR>0rgR?Ba*Wz{Fb?fG8GqRonNE5%>)!B2i#wsU8$&tN{-?I-2y z2Ntid&(0pj>!mpOI93yoA6>lOysUDa|4t0Z-%z~Xc!Q<|-KSOPwt)QoCHbO7x-T#t zEc{`$o^1+`HZ0%ouSL;|tMzPAXhi$exc5##f9ZRcM#XWdsg2L4qUV#@#ef(8X&w5X z;1-yVtDQG28dj=D&7W0YEsEFI7w3bE*GstG-a3}#H~8kh`3Mu;&H+9B0@ud|u3ufe zUW&itP7TQ4Q@q}Mbp+P^&ywQxUDmy{ntEe(+`c`3c&~)J9{IxPb4T~=?7)FVjr|9V8ZcLP^jtH z>x84bcJ8pQ+~_fVMvW<6I_`v%YL4lIzD^x`6l#v^^27E=cd7Z|vB#cxOwXF0N4M{C zObKJ?kiPwD`i&mDIzWYWO)N4;7nODH*|k`os*avrJCrJ;XP>@92NXt+=|5uZn0D=s z>(aS>hnfRg9nk8a)jHPle6^CA(L*K-D4acd#3&P9D*|P-^;l3YTr;45pD}&b34OW5 z=rN;)4j8_!4K+2zK=eDSrr+SRY6kWhGV~j6>w;C*TK2gyW#Dyce{JctTg5lVyX%Va z>YAw;)@R7KOfC6UvbR`qMPG`&=o@QG@vNyCG;GB1vOuv}3>z@4_&*ovKYB#X;6B6q z7we?R?Kkq=Zv^&lU97?%7R&b^GQ4K&=mGuLbkb7wmO9m%Hc)DCg<-|+J)++?cv>0A6A zGphVMSbr5A88B*Oq1EsaV+OQ3x_#&GkLfcAYS8ept@@4~GPM8qhx9MBDp7;`6vw?* z{m&g<)K~r;GpfuPH(=E0;?TGbQB&lN8Zfj^sQ`bC96F}ZYIRk$D*oAO(1;>AX2AI3 ze@la0QE0^Kp3-W-V1~89{fkOOm5Y|gw{i*nT`E<=Dk@lQSD#@+`W62u^}1HY+AFjw z4z$CHgXj8g3#r#i%Ob^Fd2vo${-@`4{c61l_G(%EUHWZN{C{bUN9FZguixfH-rE0) zx3hKr?O&wUF0bc*{qDMsbZM@??!S&j@{8gckMOllpkLX~a!`2@X)P5e6#p)*fvNn1 z{Gs2!mV#6KS6aR*{i*p$ai+KWU+KMD@z%Yjyw)A`t97=rbXkY~F8!9CcS>tm!q@tQ zep@0e`z5E}((`0#O-!`bG4xw{ZY}+D`^#4gg$cz!N-vY0*|1YC_dlYJ2 zM8D06U#WcQS=`G{DPAjylkeswVqh!e!Kp!E;80GuXPsvKCgoO7M~ba|I=^z z`T84tt;gtB_EKz({kmQ{XKQVIt=s6ghZcNMAYAFY&C2V!NWWSimAtqA*_2oPX}+)D zA8COZ1+rWEeq-geUZmeMB*?GhKVs#zuB6{bseh?){HKeI;_A%mK2(y?`qO?-mpyWM z(fVClEVJcW<+V{dG{Jr=Kn&pLa%Ez2eDS%XymL*@1RPbM0uCT9ThKZP`psOw%?j7v(l}mPo0B~ne@krH izIOQsw=etuZ)>o^m2BzRYJKJJ-ML(TGb> +#include +#include +#include +#include + +#include + +#include "common.h" + +// Fix for Linux <3.12 +#ifndef EM_ARM +#define EM_ARM 40 +#endif + +#define SYSCALL_LIST_DECL(arch) \ + extern const struct syscall_descriptor arch##_syscall_list[]; \ + extern const size_t arch##_syscall_list_size; + +#define SYSCALL_LIST(flag, arch, pointer_size) \ + { flag, pointer_size, arch##_syscall_list, &arch##_syscall_list_size } + +SYSCALL_LIST_DECL(arm) +SYSCALL_LIST_DECL(aarch64) +SYSCALL_LIST_DECL(amd64) +SYSCALL_LIST_DECL(mipso32) +SYSCALL_LIST_DECL(mips64) +SYSCALL_LIST_DECL(i386) + +struct syscall_list { + uint32_t arch_mask; + int pointer_size; + const struct syscall_descriptor* const syscalls; + const size_t* const size; +}; + +const struct syscall_list syscall_lists[] = { +#ifdef AUDIT_ARCH_ARM + SYSCALL_LIST(SYSCALLDB_ARCH_ARM_FLAG, arm, 4), +#endif +#ifdef AUDIT_ARCH_AARCH64 + SYSCALL_LIST(SYSCALLDB_ARCH_AARCH64_FLAG, aarch64, 8), +#endif +#ifdef AUDIT_ARCH_X86_64 + SYSCALL_LIST(SYSCALLDB_ARCH_X86_64_FLAG, amd64, 8), +#endif +#ifdef AUDIT_ARCH_MIPS + SYSCALL_LIST(SYSCALLDB_ARCH_MIPS_FLAG, mipso32, 4), +#endif +#ifdef AUDIT_ARCH_MIPS64 + SYSCALL_LIST(SYSCALLDB_ARCH_MIPS64_FLAG, mips64, 8), +#endif +#ifdef AUDIT_ARCH_I386 + SYSCALL_LIST(SYSCALLDB_ARCH_I386_FLAG, i386, 4), +#endif +}; + +enum { NARCH = sizeof(syscall_lists) / sizeof(syscall_lists[0]) }; + +struct syscall_name { + const char* name; + uint32_t definition_offset; +}; + +struct ctx { + struct arch_ctx { + uint32_t arch_mask; + int pointer_size; + const struct syscall_descriptor** syscall; + } arch[NARCH]; + struct syscall_name* syscall_names; + uint32_t syscall_names_size, syscall_names_capacity; + uint32_t* syscall_definitions; + uint32_t syscall_definitions_size; + uint32_t syscall_definitions_capacity; + char* arg_name_pool; + uint32_t arg_name_pool_size; + uint32_t arg_name_pool_capacity; +}; + +static int syscall_descriptor_cmp(const void* lhs, const void* rhs) { + return strcmp((*(const struct syscall_descriptor**)lhs)->name, + (*(const struct syscall_descriptor**)rhs)->name); +} + +static int arch_cmp(const void* lhs, const void* rhs) { + uint32_t larch_mask = ((const struct arch_ctx*)lhs)->arch_mask; + uint32_t rarch_mask = ((const struct arch_ctx*)rhs)->arch_mask; + return larch_mask < rarch_mask ? -1 : larch_mask > rarch_mask ? 1 : 0; +} + +static void init(struct ctx* ctx) { + for (size_t i = 0; i < NARCH; ++i) { + const size_t size = *syscall_lists[i].size; + const struct syscall_descriptor** p; + p = malloc((sizeof *p) * (size + 1)); // NULL-terminated + for (size_t j = 0; j < size; ++j) p[j] = &syscall_lists[i].syscalls[j]; + // sort syscalls by name + qsort(p, size, sizeof *p, syscall_descriptor_cmp); + p[size] = NULL; + ctx->arch[i].arch_mask = syscall_lists[i].arch_mask; + ctx->arch[i].pointer_size = syscall_lists[i].pointer_size; + ctx->arch[i].syscall = p; + } + // sort archs by arch_mask; code assumes orthogonal arch_mask-s + qsort(ctx->arch, NARCH, sizeof ctx->arch[0], arch_cmp); +} + +#define CHECK_CAPACITY(ctx, name, size) \ + do { \ + while ((ctx)->name##_size + size > (ctx)->name##_capacity) { \ + if (!(ctx)->name##_capacity) \ + (ctx)->name##_capacity = 1024; \ + else \ + (ctx)->name##_capacity *= 2; \ + (ctx)->name = \ + realloc((ctx)->name, sizeof(ctx->name[0]) * (ctx)->name##_capacity); \ + } \ + } while (0) + +static void syscall_names_push(struct ctx* ctx, const char* name, + uint32_t offset) { + CHECK_CAPACITY(ctx, syscall_names, 1); + ctx->syscall_names[ctx->syscall_names_size].name = name; + ctx->syscall_names[ctx->syscall_names_size].definition_offset = offset; + ++ctx->syscall_names_size; +} + +static void syscall_definitions_push(struct ctx* ctx, uint32_t v) { + CHECK_CAPACITY(ctx, syscall_definitions, 1); + ctx->syscall_definitions[ctx->syscall_definitions_size++] = v; +} + +static uint32_t arg_name_intern(struct ctx* ctx, const char* str) { + uint32_t result, size = 1 + (uint32_t)strlen(str); + char* existing = + memmem(ctx->arg_name_pool, ctx->arg_name_pool_size, str, size); + if (existing) return (uint32_t)(existing - ctx->arg_name_pool); + CHECK_CAPACITY(ctx, arg_name_pool, size); + memcpy(ctx->arg_name_pool + (result = ctx->arg_name_pool_size), str, size); + ctx->arg_name_pool_size += size; + return result; +} + +// Find the lexicographically-minimal name in syscall descriptors +// pointed by ctx->arch[i].syscall; return the union of arch_mask-s +// of the architectures providing this syscall. +static uint32_t begin_syscall(struct ctx* ctx, const char** syscall_name) { + static const char sentinel[] = {CHAR_MAX, 0}; + uint32_t mask = 0; + const char* name_min = sentinel; + for (size_t i = 0; i != NARCH; ++i) { + int cmp; + const char* name; + if (!*ctx->arch[i].syscall) continue; + cmp = strcmp(name_min, name = (*ctx->arch[i].syscall)->name); + if (!cmp) { + mask |= ctx->arch[i].arch_mask; + } else if (cmp > 0) { + mask = ctx->arch[i].arch_mask; + name_min = name; + } + } + *syscall_name = name_min; + return mask; +} + +// Extend syscall_definitions with syscall numbers from the subset of +// syscall descriptors pointed by ctx->arch[i].syscall as indicated by +// mask; advance ctx->arch[i].syscall pointers. +static void complete_syscall(struct ctx* ctx, uint32_t mask) { + for (size_t i = 0; i < NARCH; ++i) { + if (ctx->arch[i].arch_mask & mask) { + syscall_definitions_push(ctx, (*ctx->arch[i].syscall)->nr); + if (!*(++ctx->arch[i].syscall)) ctx->arch[i].arch_mask = 0; + } + } +} + +static uint32_t get_arg_name(struct ctx* ctx, uint32_t mask, int argno, + const char** arg_name) { + size_t i = 0; + const char* name; + uint32_t result; + while (!(ctx->arch[i].arch_mask & mask) || + !(name = (*ctx->arch[i].syscall)->args[argno].name)) { + if (++i == NARCH) return 0; + } + result = ctx->arch[i].arch_mask; + *arg_name = name; + while (++i != NARCH) { + if (ctx->arch[i].arch_mask & mask && + (*ctx->arch[i].syscall)->args[argno].name && + !strcmp(name, (*ctx->arch[i].syscall)->args[argno].name)) { + result |= ctx->arch[i].arch_mask; + } + } + return result; +}; + +static uint32_t get_arg_ptr(struct ctx* ctx, uint32_t mask, int argno) { + uint32_t result = 0; + for (size_t i = 0; i != NARCH; ++i) { + if (ctx->arch[i].arch_mask & mask && + (*ctx->arch[i].syscall)->args[argno].size == ctx->arch[i].pointer_size) + result |= ctx->arch[i].arch_mask; + } + return result; +} + +static uint32_t get_arg_type(struct ctx* ctx, uint32_t mask, int argno, + int* arg_type) { + size_t i = 0; + int type; + uint32_t result; + while (!(ctx->arch[i].arch_mask & mask)) { + if (++i == NARCH) return 0; + } + result = ctx->arch[i].arch_mask; + *arg_type = type = (*ctx->arch[i].syscall)->args[argno].size; + while (++i != NARCH) { + if (ctx->arch[i].arch_mask & mask && + (*ctx->arch[i].syscall)->args[argno].size == type) + result |= ctx->arch[i].arch_mask; + } + return result; +} + +static void do_arg(struct ctx* ctx, uint32_t mask, int argno) { + uint32_t namemask; + const char* name; + while ((namemask = get_arg_name(ctx, mask, argno, &name))) { + uint32_t iname = arg_name_intern(ctx, name); + uint32_t typemask; + int type; + mask &= ~namemask; + if (get_arg_ptr(ctx, namemask, argno) == namemask) { + syscall_definitions_push(ctx, namemask); + syscall_definitions_push(ctx, SYSCALLDB_ARGNO(argno) | + SYSCALLDB_ARGTYPE(0) | + SYSCALLDB_ARGNAME(iname)); + continue; + } + while ((typemask = get_arg_type(ctx, namemask, argno, &type))) { + namemask &= ~typemask; + if (type <= 0 || type > SYSCALLDB_MAX_ARGTYPE) { + fprintf(stderr, + "Syscall %s, argument #%d (%s): " + "invalid argument size: %d\n", + ctx->syscall_names[ctx->syscall_names_size - 1].name, argno, + name, type); + exit(EXIT_FAILURE); + } + syscall_definitions_push(ctx, typemask); + syscall_definitions_push(ctx, SYSCALLDB_ARGNO(argno) | + SYSCALLDB_ARGTYPE(type) | + SYSCALLDB_ARGNAME(iname)); + } + } +} + +static uint32_t compress_args(struct ctx* ctx, uint32_t mask, + uint32_t firstargoff) { + uint32_t narg = (ctx->syscall_definitions_size - firstargoff) / 2; + for (uint32_t i = firstargoff; i != ctx->syscall_definitions_size; i += 2) + if (ctx->syscall_definitions[i] != mask) return -narg; + for (uint32_t i = 0; i != narg; ++i) { + ctx->syscall_definitions[firstargoff + i] = + ctx->syscall_definitions[firstargoff + i * 2 + 1]; + } + ctx->syscall_definitions_size = firstargoff + narg; + return narg; +} + +static void write_pointer_size() { + fputs("static const int syscalldb_pointer_size[] = {\n ", stdout); + for (int i = 0; i != NARCH; ++i) { + printf(", [%d] = %d" + !i, __builtin_ctz(syscall_lists[i].arch_mask), + syscall_lists[i].pointer_size); + } + fputs("\n};\n\n", stdout); +} + +static void write_syscall_definitions(const struct ctx* ctx) { + const struct syscalldb_definition* def = + (typeof(def))ctx->syscall_definitions; + const struct syscall_name* syscall_name = ctx->syscall_names; + fputs("static const uint32_t syscalldb_definitions[] = {\n\n", stdout); + for (; def->arch_mask; def = SYSCALLDB_DEFINITION_NEXT(def), ++syscall_name) { + printf(" // %s\n %#" PRIx32 ", ", syscall_name->name, def->arch_mask); + if (def->n_arg_info <= INT32_MAX) { + printf("%" PRId32 ",\n", def->n_arg_info); + for (uint32_t i = 0; i != def->n_arg_info; ++i) { + printf(" ARGNO(%d) | ARGTYPE(%d) | ARGNAME(%d), // %s\n", + (int)SYSCALLDB_GET_ARGNO(def->arg_info[i]), + (int)SYSCALLDB_GET_ARGTYPE(def->arg_info[i]), + (int)SYSCALLDB_GET_ARGNAME(def->arg_info[i]), + ctx->arg_name_pool + SYSCALLDB_GET_ARGNAME(def->arg_info[i])); + } + } else { + printf("-%" PRId32 ",\n", -def->n_arg_info); + for (uint32_t i = 0; i != -def->n_arg_info; ++i) { + printf(" %#" PRIx32 ", ARGNO(%d) | ARGTYPE(%d) | ARGNAME(%d), // %s\n", + def->ext_arg_info[i].arch_mask, + (int)SYSCALLDB_GET_ARGNO(def->ext_arg_info[i].arg_info), + (int)SYSCALLDB_GET_ARGTYPE(def->ext_arg_info[i].arg_info), + (int)SYSCALLDB_GET_ARGNAME(def->ext_arg_info[i].arg_info), + ctx->arg_name_pool + + SYSCALLDB_GET_ARGNAME(def->ext_arg_info[i].arg_info)); + } + } + for (int i = 0; i != __builtin_popcount(def->arch_mask); ++i) { + printf(" %" PRId32 "," + (i != 0), SYSCALLDB_DEFINITION_NR(def)[i]); + } + fputs("\n\n", stdout); + } + fputs(" 0\n};\n\n", stdout); +} + +static void write_arg_name_pool(const struct ctx* ctx) { + fputs("static const char syscalldb_arg_name_pool[] =\n ", stdout); + uint32_t i = 0; + int pos = 1; + while (i != ctx->arg_name_pool_size) { + size_t len = strlen(ctx->arg_name_pool + i); + pos += 5 + (int)len; + if (pos >= 72) { + fputs("\n ", stdout); + pos = 1; + continue; + } + printf(" \"%s\\0\"", ctx->arg_name_pool + i); + i += (uint32_t)len + 1; + } + fputs(";\n\n", stdout); +} + +int main() { + struct ctx ctx = {}; + uint32_t mask; + const char* name; + init(&ctx); + while ((mask = begin_syscall(&ctx, &name))) { + uint32_t firstargoff; + syscall_names_push(&ctx, name, ctx.syscall_definitions_size); + syscall_definitions_push(&ctx, mask); + syscall_definitions_push(&ctx, 0); + firstargoff = ctx.syscall_definitions_size; + for (int argno = 0; argno < SYSCALL_MAX_ARGS; ++argno) { + do_arg(&ctx, mask, argno); + } + ctx.syscall_definitions[firstargoff - 1] = + compress_args(&ctx, mask, firstargoff); + complete_syscall(&ctx, mask); + } + syscall_definitions_push(&ctx, 0); + if (ctx.arg_name_pool_size > SYSCALLDB_MAX_ARGNAME) { + fprintf(stderr, + "String pool size exceeds %d, " + "consider increasing SYSCALLDB_MAX_ARGNAME\n", + (int)SYSCALLDB_MAX_ARGNAME); + exit(EXIT_FAILURE); + } + // Produce output in gperf format + fputs( + "%{\n" + "#include \"syscalldb.h\"\n" + "\n" + "#define ARGNO(no) SYSCALLDB_ARGNO(no)\n" + "#define ARGTYPE(type) SYSCALLDB_ARGTYPE(type)\n" + "#define ARGNAME(name) SYSCALLDB_ARGNAME(name)\n" + "\n", + stdout); + write_pointer_size(); + write_syscall_definitions(&ctx); + write_arg_name_pool(&ctx); + fputs( + "%}\n" + "%struct-type\n" + "%readonly-tables\n" + "%global-table\n" + "%pic\n" + "%define initializer-suffix ,-1\n" + "%define word-array-name syscalldb_entries\n" + "%define string-pool-name syscalldb_name_pool\n" + "%define lookup-function-name syscalldb_lookup_internal\n" + "struct syscalldb_entry;\n" + "%%\n", + stdout); + for (uint32_t i = 0; i != ctx.syscall_names_size; ++i) { + printf("%s, %u\n", ctx.syscall_names[i].name, + ctx.syscall_names[i].definition_offset); + } + fputs( + "%%\n" + "#include \"syscalldb.inl\"\n", + stdout); + return 0; +}