diff options
author | Dmitry V. Levin <ldv@strace.io> | 2021-11-13 08:00:00 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@strace.io> | 2021-11-13 08:00:00 +0000 |
commit | 5ea8888ff8fbf224812651fd07e7873239a4782a (patch) | |
tree | 131cc7719bbe46eceed3d35f4741708353eb7fbc | |
parent | 5cad0ff0f30c2729fca215c733dac83e19752040 (diff) | |
download | strace-5ea8888ff8fbf224812651fd07e7873239a4782a.tar.gz |
maint/gen: cleanup
* maint/gen/xmalloc.c: New file.
* maint/gen/xmalloc.h: Likewise.
* maint/gen/Makefile: Rewrite.
* maint/gen/codegen.c: Add copyright header, wrap very long lines,
use CLEANUP_FREE, xstrdup, and xasprintf.
* maint/gen/ast.c: Add copyright header, wrap very long lines,
use xstrdup.
* maint/gen/ast.h: Add copyright header, wrap very long lines.
* maint/gen/deflang.h: Add copyright header and include guard,
wrap very long lines, add attributes to prototypes.
* maint/gen/lex.l: Add copyright header, wrap very long lines,
fix warnings, use xstrdup.
* maint/gen/parse.y: Add copyright header, wrap very long lines,
fix warnings.
* maint/gen/preprocess.c: Add copyright header, wrap very long lines.
* maint/gen/preprocess.h: Include "ast.h".
* maint/gen/symbols.c: Wrap very long lines, use xasprintf.
* maint/gen/symbols.h: Wrap very long lines.
* maint/gen/defs/common.def: Add copyright header.
-rw-r--r-- | maint/gen/.gitignore | 9 | ||||
-rw-r--r-- | maint/gen/Makefile | 34 | ||||
-rw-r--r-- | maint/gen/ast.c | 113 | ||||
-rw-r--r-- | maint/gen/ast.h | 57 | ||||
-rw-r--r-- | maint/gen/codegen.c | 483 | ||||
-rw-r--r-- | maint/gen/deflang.h | 36 | ||||
-rw-r--r-- | maint/gen/defs/common.def | 11 | ||||
-rw-r--r-- | maint/gen/lex.l | 62 | ||||
-rw-r--r-- | maint/gen/parse.y | 68 | ||||
-rw-r--r-- | maint/gen/preprocess.c | 72 | ||||
-rw-r--r-- | maint/gen/preprocess.h | 36 | ||||
-rw-r--r-- | maint/gen/symbols.c | 39 | ||||
-rw-r--r-- | maint/gen/symbols.h | 9 | ||||
-rw-r--r-- | maint/gen/xmalloc.c | 78 | ||||
-rw-r--r-- | maint/gen/xmalloc.h | 36 |
15 files changed, 708 insertions, 435 deletions
diff --git a/maint/gen/.gitignore b/maint/gen/.gitignore index d690f4c72..33ca87140 100644 --- a/maint/gen/.gitignore +++ b/maint/gen/.gitignore @@ -1,6 +1,5 @@ -lex.yy.c -parse.tab.c -parse.tab.h -parse -parse.output +/lex.yy.c +/parse.tab.c +/parse.tab.h +/*.d /gen diff --git a/maint/gen/Makefile b/maint/gen/Makefile index 85d35d20d..f67a5ccd0 100644 --- a/maint/gen/Makefile +++ b/maint/gen/Makefile @@ -1,16 +1,34 @@ -CFLAGS += -ggdb -std=gnu99 -Wall -Wextra +# Copyright (c) 2021 Dmitry V. Levin <ldv@strace.io> +# Copyright (c) 2021 The strace developers. +# All rights reserved. +# +# SPDX-License-Identifier: LGPL-2.1-or-later -all: gen +CPPFLAGS = -std=gnu99 -O2 -D_GNU_SOURCE=1 -Wall -Wextra +TARGET = gen +OBJ = parse.tab.o lex.yy.o ast.o codegen.o symbols.o preprocess.o xmalloc.o +DEPS = $(OBJ:.o=.d) -gen: parse.tab.o lex.yy.o ast.o codegen.o symbols.o parse.tab.h lex.yy.c preprocess.o - $(CC) $(CFLAGS) parse.tab.o lex.yy.o ast.o codegen.o symbols.o preprocess.o -o ./gen +all: $(TARGET) + +gen: $(OBJ) + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ -o $@ lex.yy.c: lex.l parse.tab.h - flex lex.l + flex $< parse.tab.c parse.tab.h: parse.y - bison -d parse.y + bison -d $< clean: - rm -f lex.yy.o ast.o parse.tab.o codegen.o preprocess.o symbols.o - rm -f gen parse.tab.c parse.tab.h lex.yy.c lex.yy.h + $(RM) $(TARGET) $(OBJ) $(DEPS) \ + parse.tab.c parse.tab.h lex.yy.c + +%.d: %.c + $(CC) -MM $(CPPFLAGS) $< -o $@ + +$(DEPS): parse.tab.h + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPS) +endif diff --git a/maint/gen/ast.c b/maint/gen/ast.c index ebab08538..ede0641ea 100644 --- a/maint/gen/ast.c +++ b/maint/gen/ast.c @@ -1,39 +1,20 @@ -#include "ast.h" +/* + * Copyright (c) 2021 Srikavin Ramkumar <srikavinramkumar@gmail.com> + * Copyright (c) 2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> +#include "ast.h" #include "deflang.h" #include "symbols.h" #include "parse.tab.h" -void * -xmalloc(size_t n) -{ - void *ret = malloc(n); - - if (!ret) { - fprintf(stderr, "allocation failed\n"); - exit(EXIT_FAILURE); - } - - return ret; -} - -void * -xcalloc(size_t n) -{ - void *ret = calloc(1, n); - - if (!ret) { - fprintf(stderr, "allocation failed\n"); - exit(EXIT_FAILURE); - } - - return ret; -} - struct ast_node * create_ast_node(enum ast_node_type type, void *loc) { @@ -43,7 +24,7 @@ create_ast_node(enum ast_node_type type, void *loc) .loc = { .lineno = ((YYLTYPE *) loc)->first_line, .colno = ((YYLTYPE *) loc)->first_column, - .file = strdup(cur_filename) + .file = xstrdup(cur_filename) }, .next = NULL }; @@ -51,7 +32,8 @@ create_ast_node(enum ast_node_type type, void *loc) } struct ast_type_option_list * -create_ast_type_option_list(struct ast_type_option *cur, struct ast_type_option_list *next) +create_ast_type_option_list(struct ast_type_option *cur, + struct ast_type_option_list *next) { struct ast_type_option_list *list = xmalloc(sizeof *list); *list = (struct ast_type_option_list) { @@ -62,7 +44,8 @@ create_ast_type_option_list(struct ast_type_option *cur, struct ast_type_option_ } struct ast_syscall_arg * -create_ast_syscall_arg(char *name, struct ast_type *type, struct ast_syscall_arg *next) +create_ast_syscall_arg(char *name, struct ast_type *type, + struct ast_syscall_arg *next) { struct ast_syscall_arg *arg = xmalloc(sizeof *arg); *arg = (struct ast_syscall_arg) { @@ -85,9 +68,11 @@ create_ast_flag_values(char *name, struct ast_flag_values *next) } struct ast_struct_element * -create_ast_struct_element(char *name, struct ast_type *type, struct ast_struct_element *next) +create_ast_struct_element(char *name, struct ast_type *type, + struct ast_struct_element *next) { - struct ast_struct_element *struct_element = xmalloc(sizeof *struct_element); + struct ast_struct_element *struct_element = + xmalloc(sizeof *struct_element); *struct_element = (struct ast_struct_element) { .name = name, .type = type, @@ -111,8 +96,9 @@ struct known_type_option { static struct known_type_option *known_type_options = NULL; static bool -compare_type_option_list(struct ast_type_option_list *a, struct ast_type_option_list *b, - bool match_templates) +compare_type_option_list(struct ast_type_option_list *a, + struct ast_type_option_list *b, + bool match_templates) { struct ast_type_option_list *cur_a = a; struct ast_type_option_list *cur_b = b; @@ -123,9 +109,9 @@ compare_type_option_list(struct ast_type_option_list *a, struct ast_type_option_ } if (cur_a->option->child_type == AST_TYPE_CHILD_TEMPLATE_ID || - cur_b->option->child_type == AST_TYPE_CHILD_TEMPLATE_ID) { + cur_b->option->child_type == AST_TYPE_CHILD_TEMPLATE_ID) { if (match_templates) { - // templates are able to match all other type options + /* templates can match all other type options */ cur_a = cur_a->next; cur_b = cur_b->next; continue; @@ -138,14 +124,16 @@ compare_type_option_list(struct ast_type_option_list *a, struct ast_type_option_ } if (cur_a->option->child_type == AST_TYPE_CHILD_NUMBER && - (cur_a->option->number.val != cur_b->option->number.val)) { + cur_a->option->number.val != cur_b->option->number.val) { return false; } if (cur_a->option->child_type == AST_TYPE_CHILD_TYPE) { - if (!(strcmp(cur_a->option->type->name, cur_b->option->type->name) == 0 && - compare_type_option_list(cur_a->option->type->options, - cur_b->option->type->options, match_templates))) { + if (!(strcmp(cur_a->option->type->name, + cur_b->option->type->name) == 0 && + compare_type_option_list(cur_a->option->type->options, + cur_b->option->type->options, + match_templates))) { return false; } } @@ -164,21 +152,23 @@ compare_type_option_list(struct ast_type_option_list *a, struct ast_type_option_ bool ast_type_matching(struct ast_type *a, struct ast_type *b) { - return strcmp(a->name, b->name) == 0 && compare_type_option_list(a->options, b->options, true); + return strcmp(a->name, b->name) == 0 && + compare_type_option_list(a->options, b->options, true); } struct ast_type * create_or_get_type(char **error, char *name, struct ast_type_option_list *options) { - // check if we've seen this type before - for (struct known_type *cur = known_types; cur != NULL; cur = cur->next) { + /* check if we've seen this type before */ + for (struct known_type *cur = known_types; + cur != NULL; cur = cur->next) { if (strcmp(cur->type.name, name) == 0 && - compare_type_option_list(cur->type.options, options, false)) { + compare_type_option_list(cur->type.options, options, false)) { return &cur->type; } } - // allocate a new type + /* allocate a new type */ struct known_type *type = xmalloc(sizeof *type); char *status = resolve_type(&type->type, name, options); @@ -201,15 +191,16 @@ create_or_get_type(char **error, char *name, struct ast_type_option_list *option struct ast_type_option * create_or_get_type_option_number(struct ast_number number) { - // check if we've seen this type option before - for (struct known_type_option *cur = known_type_options; cur != NULL; cur = cur->next) { + /* check if we've seen this type option before */ + for (struct known_type_option *cur = known_type_options; + cur != NULL; cur = cur->next) { if (cur->type_option.child_type == AST_TYPE_CHILD_NUMBER && - cur->type_option.number.val == number.val) { + cur->type_option.number.val == number.val) { return &cur->type_option; } } - // allocate a new type option + /* allocate a new type option */ struct known_type_option *option = xmalloc(sizeof *option); *option = (struct known_type_option) { .type_option = { @@ -241,16 +232,20 @@ create_type_template_identifier(struct ast_number number) struct ast_type_option * create_or_get_type_option_nested(struct ast_type *child) { - // check if we've seen this type option before - for (struct known_type_option *cur = known_type_options; cur != NULL; cur = cur->next) { - // since all types are allocated by create_or_get_type, - // types that are equal have the same address - if (cur->type_option.child_type == AST_TYPE_CHILD_TYPE && cur->type_option.type == child) { + /* check if we've seen this type option before */ + for (struct known_type_option *cur = known_type_options; + cur != NULL; cur = cur->next) { + /* + * Since all types are allocated by create_or_get_type, + * types that are equal have the same address. + */ + if (cur->type_option.child_type == AST_TYPE_CHILD_TYPE && + cur->type_option.type == child) { return &cur->type_option; } } - // allocate a new type option + /* allocate a new type option */ struct known_type_option *option = xmalloc(sizeof *option); *option = (struct known_type_option) { .type_option = { @@ -266,7 +261,8 @@ create_or_get_type_option_nested(struct ast_type *child) } struct ast_type_option * -create_type_option_range(struct ast_type_option *min, struct ast_type_option *max) +create_type_option_range(struct ast_type_option *min, + struct ast_type_option *max) { struct ast_type_option *ret = xmalloc(sizeof *ret); *ret = (struct ast_type_option) { @@ -294,7 +290,8 @@ free_ast_tree(struct ast_node *root) free(root->include.value); break; case AST_STRUCT: { - struct ast_struct_element *cur = root->ast_struct.elements; + struct ast_struct_element *cur = + root->ast_struct.elements; while (cur != NULL) { struct ast_struct_element *tmp = cur; cur = tmp->next; diff --git a/maint/gen/ast.h b/maint/gen/ast.h index 2a5ee9805..863865c54 100644 --- a/maint/gen/ast.h +++ b/maint/gen/ast.h @@ -1,8 +1,16 @@ +/* + * Copyright (c) 2021 Srikavin Ramkumar <srikavinramkumar@gmail.com> + * Copyright (c) 2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + #ifndef AST_H -#define AST_H +# define AST_H -#include <stdbool.h> -#include <stdint.h> +# include <stdbool.h> +# include <stdint.h> struct ast_number { char *raw; @@ -44,27 +52,27 @@ struct ast_syscall_arg { }; enum standard_types { - // non-special type + /* non-special type */ TYPE_BASIC, - // const[typ, val] + /* const[typ, val] */ TYPE_CONST, - // ptr[dir, typ] + /* ptr[dir, typ] */ TYPE_PTR, - // ref[argname] + /* ref[argname] */ TYPE_REF, - // xorflags[flag_typ] + /* xorflags[flag_typ] */ TYPE_XORFLAGS, - // orflags[flag_typ] + /* orflags[flag_typ] */ TYPE_ORFLAGS }; -#define IS_IN_PTR(x) ((x)->type == TYPE_PTR && \ +# define IS_IN_PTR(x) ((x)->type == TYPE_PTR && \ ((x)->ptr.dir == PTR_DIR_INOUT || (x)->ptr.dir == PTR_DIR_IN)) -#define IS_OUT_PTR(x) ((x)->type == TYPE_PTR && \ +# define IS_OUT_PTR(x) ((x)->type == TYPE_PTR && \ ((x)->ptr.dir == PTR_DIR_INOUT || (x)->ptr.dir == PTR_DIR_OUT)) -#define IS_INOUT_PTR(x) ((x)->type == TYPE_PTR && (x)->ptr.dir == PTR_DIR_INOUT) +# define IS_INOUT_PTR(x) ((x)->type == TYPE_PTR && (x)->ptr.dir == PTR_DIR_INOUT) enum ptr_dir { PTR_DIR_IN, @@ -94,7 +102,7 @@ struct ast_type { } array; struct { bool return_value; - // only set if return_value is false + /* only set if return_value is false */ char *argname; } ref; struct { @@ -152,7 +160,7 @@ struct ast_node { enum ast_node_type type; struct ast_loc loc; - // used when this node's parent is AST_COMPOUND + /* used when this node's parent is AST_COMPOUND */ struct ast_node *next; union { @@ -187,26 +195,28 @@ struct ast_node * create_ast_node(enum ast_node_type type, void *location); struct ast_type_option_list * -create_ast_type_option_list(struct ast_type_option *cur, struct ast_type_option_list *next); +create_ast_type_option_list(struct ast_type_option *cur, + struct ast_type_option_list *next); struct ast_struct_element * -create_ast_struct_element(char *name, struct ast_type *type, struct ast_struct_element *next); +create_ast_struct_element(char *name, struct ast_type *type, + struct ast_struct_element *next); struct ast_syscall_arg * -create_ast_syscall_arg(char *name, struct ast_type *type, struct ast_syscall_arg *next); +create_ast_syscall_arg(char *name, struct ast_type *type, + struct ast_syscall_arg *next); struct ast_flag_values * create_ast_flag_values(char *name, struct ast_flag_values *next); -// returns true if two types are equal; false otherwise +/* Returns true if two types are equal; false otherwise. */ bool ast_type_matching(struct ast_type *a, struct ast_type *b); -/* - * On error, returns NULL and sets an error string to error. - */ +/* On error, returns NULL and sets an error string to error. */ struct ast_type * -create_or_get_type(char **error, char *name, struct ast_type_option_list *options); +create_or_get_type(char **error, char *name, + struct ast_type_option_list *options); struct ast_type_option * create_or_get_type_option_number(struct ast_number number); @@ -215,7 +225,8 @@ struct ast_type_option * create_or_get_type_option_nested(struct ast_type *child); struct ast_type_option * -create_type_option_range(struct ast_type_option *min, struct ast_type_option *max); +create_type_option_range(struct ast_type_option *min, + struct ast_type_option *max); struct ast_type_option * create_type_template_identifier(struct ast_number number); diff --git a/maint/gen/codegen.c b/maint/gen/codegen.c index 05dfb08a5..8f2e0653b 100644 --- a/maint/gen/codegen.c +++ b/maint/gen/codegen.c @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2021 Srikavin Ramkumar <srikavinramkumar@gmail.com> + * Copyright (c) 2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + #include <assert.h> #include <ctype.h> #include <inttypes.h> @@ -50,11 +58,6 @@ char *unsigned_int_types[] = { static struct decoder_list *decoders = NULL; -#define VARIANT_FUNC_NAME_LEN 64 -#define SYSCALL_RET_FLAG_LEN 64 -#define SYSCALL_ARG_STR_LEN 16 -#define DECODER_PROTOTYPE_LEN 128 - #define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0])) /* convenience macros */ @@ -169,28 +172,28 @@ is_unsigned_integer_typename(const char *name) /* * Stores a string referring to the i-th argument in the current syscall. */ -static void -get_syscall_arg_value(char out[static SYSCALL_ARG_STR_LEN], struct syscall *syscall, size_t i) +static char * +get_syscall_arg_value(struct syscall *syscall, size_t i) { if (syscall->is_ioctl) { if (i >= 1 && i <= 2) { const char *ioctl_args[3] = {"", "code", "arg"}; - snprintf(out, SYSCALL_ARG_STR_LEN, "%s", ioctl_args[i]); - return; + return xstrdup(ioctl_args[i]); } - log_warning("ioctl decoder referenced OOB argument %zu", syscall->loc, i); + log_warning("ioctl decoder referenced OOB argument %zu", + syscall->loc, i); } - snprintf(out, SYSCALL_ARG_STR_LEN, "tcp->u_arg[%zu]", i); + return xasprintf("tcp->u_arg[%zu]", i); } /* * Stores a string referring to the return value of the current syscall. */ -static void -get_syscall_ret_value(char out[static SYSCALL_ARG_STR_LEN]) +static char * +get_syscall_ret_value() { - snprintf(out, SYSCALL_ARG_STR_LEN, "tcp->u_rval"); + return xstrdup("tcp->u_rval"); } /* @@ -208,22 +211,14 @@ type_to_ctype(const struct ast_type *type) struct ast_node *def = symbol_get(type->name); if (def != NULL && def->type == AST_STRUCT) { - size_t len = sizeof("struct ") + strlen(type->name); - char *ret = xmalloc(len); - snprintf(ret, len, "struct %s", type->name); - return ret; + return xasprintf("struct %s", type->name); } return type->name; } if (type->type == TYPE_PTR) { - char *underlying = type_to_ctype(type->ptr.type); - - size_t len = strlen(underlying) + sizeof(" *"); - char *ret = xmalloc(len); - snprintf(ret, len, "%s *", underlying); - return ret; + return xasprintf("%s *", type_to_ctype(type->ptr.type)); } if (type->type == TYPE_XORFLAGS) { @@ -241,36 +236,27 @@ static char * type_variable_declaration(const struct ast_type *type, const char *var_name) { if (type->type == TYPE_BASIC && strcmp(type->name, "array") == 0) { if (type->options != NULL && type->options->next != NULL) { - struct ast_type_option *underlying_type = type->options->option; - struct ast_type_option *member_count_type = type->options->next->option; + struct ast_type_option *underlying_type = + type->options->option; + struct ast_type_option *member_count_type = + type->options->next->option; if (underlying_type->child_type == AST_TYPE_CHILD_TYPE && - member_count_type->child_type == AST_TYPE_CHILD_NUMBER) { - char *underlying = type_to_ctype(underlying_type->type); - - size_t len = strlen(underlying) + sizeof("() [];") + strlen(var_name) + strlen(member_count_type->number.raw); - char *ret = xmalloc(len); - snprintf(ret, len, "%s %s[%s];", underlying, var_name, member_count_type->number.raw); - - return ret; + member_count_type->child_type == AST_TYPE_CHILD_NUMBER) { + return xasprintf("%s %s[%s];", + type_to_ctype(underlying_type->type), + var_name, member_count_type->number.raw); } } } - char *underlying = type_to_ctype(type); - - size_t len = strlen(underlying) + strlen(var_name) + sizeof(" ;"); - char *ret = xmalloc(len); - snprintf(ret, len, "%s %s;", underlying, var_name); - - return ret; + return xasprintf("%s %s;", type_to_ctype(type), var_name); } /* * Get flags to return from a SYS_FUNC. */ -static void -get_sys_func_return_flags(char out[static SYSCALL_RET_FLAG_LEN], struct ast_type *type, - bool is_ioctl) +static char * +get_sys_func_return_flags(struct ast_type *type, bool is_ioctl) { struct { char *type; @@ -297,9 +283,9 @@ get_sys_func_return_flags(char out[static SYSCALL_RET_FLAG_LEN], struct ast_type } if (following) { - snprintf(out, SYSCALL_RET_FLAG_LEN, "%s | %s", base, following); + return xasprintf("%s | %s", base, following); } else { - snprintf(out, SYSCALL_RET_FLAG_LEN, "%s", base); + return xasprintf("%s", base); } } @@ -313,47 +299,46 @@ get_sys_func_return_flags(char out[static SYSCALL_RET_FLAG_LEN], struct ast_type * The specified type option MUST NOT be a range or a template id. */ static char * -resolve_type_option_to_value(struct syscall *syscall, struct ast_type_option *option) +resolve_type_option_to_value(struct syscall *syscall, + struct ast_type_option *option) { assert(option->child_type != AST_TYPE_CHILD_RANGE && - option->child_type != AST_TYPE_CHILD_TEMPLATE_ID); + option->child_type != AST_TYPE_CHILD_TEMPLATE_ID); if (option->child_type == AST_TYPE_CHILD_NUMBER) { - // return the number exactly as specified in the source file + /* return the number exactly as specified in the source file */ return option->number.raw; } else if (option->child_type == AST_TYPE_CHILD_TYPE) { if (option->type->type == TYPE_REF) { - // identify which argument is being referred to + /* identify which argument is being referred to */ - // syscall return value + /* syscall return value */ if (option->type->ref.return_value) { - char *ret = xmalloc(SYSCALL_ARG_STR_LEN); - get_syscall_ret_value(ret); - return ret; + return get_syscall_ret_value(); } - // find syscall argument by name + /* find syscall argument by name */ bool found = false; size_t index = 0; for (; index < syscall->arg_count; ++index) { - if (strcmp(option->type->ref.argname, syscall->args[index].name) == 0) { + if (strcmp(option->type->ref.argname, + syscall->args[index].name) == 0) { found = true; break; } } if (found) { - char *ret = xmalloc(SYSCALL_ARG_STR_LEN); - get_syscall_arg_value(ret, syscall, index); - return ret; + return get_syscall_arg_value(syscall, index); } - log_warning("Failed to resolve 'ref' type with value \"%s\" to argument", - syscall->loc, option->type->ref.argname); + log_warning("Failed to resolve 'ref' type" + " with value \"%s\" to argument", + syscall->loc, option->type->ref.argname); return "#error FAILED TO RESOLVE REF TYPE TO VALUE"; } else { - // assume the given value is a constant or from a #define + /* assume the given value is a constant or from a #define */ return option->type->name; } } @@ -387,29 +372,27 @@ store_single_value(FILE *out, struct ast_type *type, char *arg, int indent_level static void generate_printer(FILE *out, struct syscall *syscall, const char *argname, - const char *arg, bool entering, - struct ast_type *type, int indent_level); + const char *arg, bool entering, + struct ast_type *type, int indent_level); static void generate_printer_ptr(FILE *out, struct syscall *syscall, const char *argname, - const char *arg, bool entering, - struct ast_type *type, int indent_level) + const char *arg, bool entering, + struct ast_type *type, int indent_level) { - struct ast_type *underlying = type->ptr.type; - - // copy from target memory and use decoder for resulting value - char var_name[32]; - snprintf(var_name, 32, "tmpvar_%s", argname); - + /* copy from target memory and use decoder for resulting value */ if ((IS_IN_PTR(type) && entering) || (IS_OUT_PTR(type) && !entering)) { - OUTFI("%s\n", type_variable_declaration(type->ptr.type, var_name)); + CLEANUP_FREE char *var_name = + xasprintf("tmpvar_%s", argname); + OUTFI("%s\n", + type_variable_declaration(type->ptr.type, var_name)); OUTFI("if (!umove_or_printaddr(tcp, %s, &%s)) {\n", - arg, var_name); + arg, var_name); indent_level++; OUTFI("tprint_indirect_begin();\n"); generate_printer(out, syscall, argname, var_name, entering, - type->ptr.type, indent_level); + type->ptr.type, indent_level); OUTFI("tprint_indirect_end();\n"); indent_level--; @@ -419,8 +402,8 @@ generate_printer_ptr(FILE *out, struct syscall *syscall, const char *argname, static void generate_templated_printer(FILE *out, struct syscall *syscall, - const char *arg, struct ast_type *arg_type, - struct decoder templated_decoder) + const char *arg, struct ast_type *arg_type, + struct decoder templated_decoder) { struct { char *value; @@ -428,7 +411,7 @@ generate_templated_printer(FILE *out, struct syscall *syscall, } substitutions[256]; int subs_pos = 0; - // Do a DFS over the template type to find substitution markers + /* Do a DFS over the template type to find substitution markers. */ struct dfs_stack_entry { struct ast_type *template; struct ast_type *actual; @@ -455,23 +438,31 @@ generate_templated_printer(FILE *out, struct syscall *syscall, continue; } - struct ast_type_option_list *template_option = entry.template->options; - struct ast_type_option_list *actual_option = entry.actual->options; + struct ast_type_option_list *template_option = + entry.template->options; + struct ast_type_option_list *actual_option = + entry.actual->options; for (; actual_option != NULL && template_option != NULL; - actual_option = actual_option->next, template_option = template_option->next) { - if (template_option->option->child_type == AST_TYPE_CHILD_TEMPLATE_ID) { - substitutions[subs_pos].value = resolve_type_option_to_value(syscall, - actual_option->option); - substitutions[subs_pos].template_id = template_option->option->template.id; + actual_option = actual_option->next, + template_option = template_option->next) { + if (template_option->option->child_type == + AST_TYPE_CHILD_TEMPLATE_ID) { + substitutions[subs_pos].value = + resolve_type_option_to_value(syscall, + actual_option->option); + substitutions[subs_pos].template_id = + template_option->option->template.id; subs_pos++; continue; } - if (actual_option->option->child_type != template_option->option->child_type) { + if (actual_option->option->child_type != + template_option->option->child_type) { break; } - if (template_option->option->child_type == AST_TYPE_CHILD_TYPE) { + if (template_option->option->child_type == + AST_TYPE_CHILD_TYPE) { dfs_stack[stack_ptr] = (struct dfs_stack_entry) { .template = template_option->option->type, .actual = actual_option->option->type @@ -481,7 +472,10 @@ generate_templated_printer(FILE *out, struct syscall *syscall, } } - // Output the template string and replace substitution markers with real values + /* + * Output the template string and replace substitution markers + * with real values. + */ const char *template = templated_decoder.fmt_string; size_t template_len = strlen(template); @@ -513,7 +507,7 @@ generate_templated_printer(FILE *out, struct syscall *syscall, in_template_number = false; int found = -1; - // find matching substitution + /* find matching substitution */ for (int j = 0; j < subs_pos; ++j) { if (substitutions[j].template_id == cur) { found = j; @@ -522,8 +516,9 @@ generate_templated_printer(FILE *out, struct syscall *syscall, } if (found == -1) { - log_warning("Template variable $%" PRIdMAX " could not be resolved!", - syscall->loc, cur); + log_warning("Template variable $%" PRIdMAX + " could not be resolved!", + syscall->loc, cur); continue; } @@ -541,14 +536,18 @@ generate_templated_printer(FILE *out, struct syscall *syscall, */ static void generate_printer(FILE *out, struct syscall *syscall, - const char *argname, const char *arg, bool entering, - struct ast_type *type, int indent_level) + const char *argname, const char *arg, bool entering, + struct ast_type *type, int indent_level) { - for (struct decoder_list *cur = decoders; cur != NULL; cur = cur->next) { + for (struct decoder_list *cur = decoders; + cur != NULL; cur = cur->next) { if (ast_type_matching(cur->decoder.matching_type, type)) { - OUTFI("/* using decoder from %s:%d:%d */\n", cur->decoder.loc.file, - cur->decoder.loc.lineno, cur->decoder.loc.colno); - generate_templated_printer(out, syscall, arg, type, cur->decoder); + OUTFI("/* using decoder from %s:%d:%d */\n", + cur->decoder.loc.file, + cur->decoder.loc.lineno, + cur->decoder.loc.colno); + generate_templated_printer(out, syscall, arg, type, + cur->decoder); OUTC('\n'); return; } @@ -556,38 +555,51 @@ generate_printer(FILE *out, struct syscall *syscall, if (type->type == TYPE_BASIC) { if (is_signed_integer_typename(type->name)) { - OUTFI("PRINT_VAL_D((%s) %s);\n", type_to_ctype(type), arg); + OUTFI("PRINT_VAL_D((%s) %s);\n", + type_to_ctype(type), arg); return; } else if (is_unsigned_integer_typename(type->name)) { - OUTFI("PRINT_VAL_U((%s) %s);\n", type_to_ctype(type), arg); + OUTFI("PRINT_VAL_U((%s) %s);\n", + type_to_ctype(type), arg); return; } - log_warning("No known printer for basic type %s", syscall->loc, type->name); - outf_indent(indent_level, out, "#error UNHANDLED BASIC TYPE: %s\n", type->name); + log_warning("No known printer for basic type %s", + syscall->loc, type->name); + outf_indent(indent_level, out, + "#error UNHANDLED BASIC TYPE: %s\n", type->name); } else if (type->type == TYPE_PTR) { - generate_printer_ptr(out, syscall, argname, arg, entering, type, indent_level); + generate_printer_ptr(out, syscall, argname, arg, entering, type, + indent_level); } else if (type->type == TYPE_ORFLAGS) { - OUTFI("printflags(%s, %s, \"%s\");\n", type->orflags.flag_type->type->name, arg, - type->orflags.dflt); + OUTFI("printflags(%s, %s, \"%s\");\n", + type->orflags.flag_type->type->name, arg, + type->orflags.dflt); } else if (type->type == TYPE_XORFLAGS) { - OUTFI("printxval(%s, %s, \"%s\");\n", type->xorflags.flag_type->type->name, arg, - type->xorflags.dflt); - } else if (strcmp(type->name, "stringnoz") == 0 || strcmp(type->name, "string") == 0) { - log_warning("Type '%s' should be wrapped in a ptr type to indicate direction", - syscall->loc, type->name); + OUTFI("printxval(%s, %s, \"%s\");\n", + type->xorflags.flag_type->type->name, arg, + type->xorflags.dflt); + } else if (strcmp(type->name, "stringnoz") == 0 || + strcmp(type->name, "string") == 0) { + log_warning("Type '%s' should be wrapped in a ptr type" + " to indicate direction", + syscall->loc, type->name); } else if (type->type == TYPE_CONST) { if (!type->constt.real_type) { - log_warning("Const type (%s) has no matching parent syscall argument.", syscall->loc, - argname); + log_warning("Const type (%s) has no matching" + " parent syscall argument.", + syscall->loc, argname); return; } - OUTFI("/* inherited parent type (%s) */\n", type_to_ctype(type->constt.real_type)); + OUTFI("/* inherited parent type (%s) */\n", + type_to_ctype(type->constt.real_type)); generate_printer(out, syscall, argname, arg, entering, - type->constt.real_type, indent_level); + type->constt.real_type, indent_level); } else { - log_warning("Type '%s' is currently unhandled", syscall->loc, type->name); - outf_indent(indent_level, out, "#error UNHANDLED TYPE: %s\n", type->name); + log_warning("Type '%s' is currently unhandled", + syscall->loc, type->name); + outf_indent(indent_level, out, + "#error UNHANDLED TYPE: %s\n", type->name); } } @@ -596,16 +608,18 @@ generate_return_flags(FILE *out, struct syscall *syscall, int indent_level) { struct ast_type ret = syscall->ret; if (ret.type == TYPE_ORFLAGS) { - OUTFI("tcp->auxstr = sprintflags(\"%s\", %s, (kernel_ulong_t) tcp->u_rval);\n", - ret.orflags.dflt, ret.orflags.flag_type->type->name); + OUTFI("tcp->auxstr = sprintflags(\"%s\", %s" + ", (kernel_ulong_t) tcp->u_rval);\n", + ret.orflags.dflt, ret.orflags.flag_type->type->name); OUTFI("return RVAL_STR;\n"); } else if (ret.type == TYPE_XORFLAGS) { - OUTFI("tcp->auxstr = xlookup(%s, (kernel_ulong_t) tcp->u_rval);\n", - ret.xorflags.flag_type->type->name); + OUTFI("tcp->auxstr = xlookup(%s" + ", (kernel_ulong_t) tcp->u_rval);\n", + ret.xorflags.flag_type->type->name); OUTFI("return RVAL_STR;\n"); } else { - char flags[SYSCALL_RET_FLAG_LEN]; - get_sys_func_return_flags(flags, &ret, syscall->is_ioctl); + CLEANUP_FREE char *flags = + get_sys_func_return_flags(&ret, syscall->is_ioctl); OUTFI("return %s;\n", flags); } } @@ -617,18 +631,17 @@ generate_return_flags(FILE *out, struct syscall *syscall, int indent_level) * The is_leaf parameter should be set if corresponding syscall is a leaf node, * i.e. has no sub syscalls. */ -static void -get_variant_function_name(char out[static VARIANT_FUNC_NAME_LEN], char *variant_name, bool is_leaf) +static char * +get_variant_function_name(char *variant_name, bool is_leaf) { - snprintf(out, VARIANT_FUNC_NAME_LEN, "var_%s%s", is_leaf ? "leaf_" : "", variant_name); - for (int i = 0; i < VARIANT_FUNC_NAME_LEN; ++i) { - if (out[i] == '\0') { - break; - } - if (out[i] == '$') { - out[i] = '_'; + char *out = xasprintf("var_%s%s", + is_leaf ? "leaf_" : "", variant_name); + for (char *p = out; *p; ++p) { + if (*p == '$') { + *p = '_'; } } + return out; } /* @@ -665,22 +678,23 @@ out_statement_condition_end(FILE *out, struct statement_condition *condition) } } -static void -get_decoder_prototype(char out[static DECODER_PROTOTYPE_LEN], bool internal, - struct syscall *syscall, char *func_name) +static char * +get_decoder_prototype(bool internal, struct syscall *syscall, char *func_name) { - snprintf(out, DECODER_PROTOTYPE_LEN, "%sint\n" - "%s(struct tcb *tcp%s)\n", + return xasprintf("%sint\n" + "%s(struct tcb *tcp%s)\n", internal ? "static " : "", func_name, - syscall->is_ioctl ? ", unsigned int code, kernel_ulong_t arg" : ""); + syscall->is_ioctl ? + ", unsigned int code, kernel_ulong_t arg" : ""); } /* * Prints out a decoder for the given system call. */ static void -generate_decoder(FILE *out, struct syscall *syscall, bool is_variant, bool ioctl_fallback) +generate_decoder(FILE *out, struct syscall *syscall, bool is_variant, + bool ioctl_fallback) { int indent_level = 0; @@ -690,12 +704,15 @@ generate_decoder(FILE *out, struct syscall *syscall, bool is_variant, bool ioctl int arg_index = 0; if (syscall->is_ioctl) { - // no need to decode code, or arg for ioctl variant syscalls + /* no need to decode code, or arg for ioctl variant syscalls */ arg_offset = 2; arg_index = 2; } - // determine which strategy to use depending on how many OUT ptrs there are + /* + * Determine which strategy to use depending on + * how many OUT ptrs there are. + */ size_t out_ptrs = 0; for (size_t i = arg_offset; i < syscall->arg_count; i++) { if (IS_OUT_PTR(syscall->args[i].type)) { @@ -703,14 +720,12 @@ generate_decoder(FILE *out, struct syscall *syscall, bool is_variant, bool ioctl } } - // output function declaration + /* output function declaration */ if (is_variant) { - char func_name[VARIANT_FUNC_NAME_LEN]; - get_variant_function_name(func_name, syscall->name, true); - - char decoder_prototype[DECODER_PROTOTYPE_LEN]; - get_decoder_prototype(decoder_prototype, true, syscall, func_name); - + CLEANUP_FREE char *func_name = + get_variant_function_name(syscall->name, true); + CLEANUP_FREE char *decoder_prototype = + get_decoder_prototype(true, syscall, func_name); OUTSI(decoder_prototype); } else { OUTFI("SYS_FUNC(%s)\n", syscall->name); @@ -725,21 +740,20 @@ generate_decoder(FILE *out, struct syscall *syscall, bool is_variant, bool ioctl return; } - char arg_val[SYSCALL_ARG_STR_LEN]; - if (out_ptrs == 0) { if (syscall->is_ioctl) { OUTFI("tprint_arg_next();\n"); } - // 0 out ptrs: print all args in sysenter + /* 0 out ptrs: print all args in sysenter */ for (size_t i = arg_offset; i < syscall->arg_count; i++) { struct syscall_argument arg = syscall->args[i]; - OUTFI("/* arg: %s (%s) */\n", arg.name, type_to_ctype(arg.type)); - get_syscall_arg_value(arg_val, syscall, arg_index++); - - generate_printer(out, syscall, arg.name, arg_val, true, arg.type, - indent_level); + OUTFI("/* arg: %s (%s) */\n", + arg.name, type_to_ctype(arg.type)); + CLEANUP_FREE char *arg_val = + get_syscall_arg_value(syscall, arg_index++); + generate_printer(out, syscall, arg.name, arg_val, true, + arg.type, indent_level); if (i < syscall->arg_count - 1) { OUTSI("tprint_arg_next();\n"); @@ -747,7 +761,10 @@ generate_decoder(FILE *out, struct syscall *syscall, bool is_variant, bool ioctl OUTC('\n'); } } else if (out_ptrs == 1) { - // == 1 out ptrs: print args until the out ptr in sysenter, rest in sysexit + /* + * == 1 out ptrs: print args until the out ptr in sysenter, + * rest in sysexit + */ size_t cur = arg_offset; OUTSI("if (entering(tcp)) {\n"); @@ -763,43 +780,54 @@ generate_decoder(FILE *out, struct syscall *syscall, bool is_variant, bool ioctl break; } - OUTFI("/* arg: %s (%s) */\n", arg.name, type_to_ctype(arg.type)); - get_syscall_arg_value(arg_val, syscall, arg_index++); - - generate_printer(out, syscall, arg.name, arg_val, true, arg.type, - indent_level); + OUTFI("/* arg: %s (%s) */\n", + arg.name, type_to_ctype(arg.type)); + CLEANUP_FREE char *arg_val = + get_syscall_arg_value(syscall, arg_index++); + generate_printer(out, syscall, arg.name, arg_val, true, + arg.type, indent_level); if (cur < syscall->arg_count - 1) { OUTSI("tprint_arg_next();\n\n"); } } - if (cur < syscall->arg_count && IS_INOUT_PTR(syscall->args[cur].type)) { - get_syscall_arg_value(arg_val, syscall, cur); - store_single_value(out, syscall->args[cur].type, arg_val, indent_level); + if (cur < syscall->arg_count && + IS_INOUT_PTR(syscall->args[cur].type)) { + CLEANUP_FREE char *arg_val = + get_syscall_arg_value(syscall, cur); + store_single_value(out, syscall->args[cur].type, + arg_val, indent_level); } OUTSI("return 0;\n"); indent_level--; OUTSI("}\n"); - if (cur < syscall->arg_count && IS_INOUT_PTR(syscall->args[cur].type)) { - // TODO: compare the current value with the previous value - // and print only if changed + if (cur < syscall->arg_count && + IS_INOUT_PTR(syscall->args[cur].type)) { + /* + * TODO: + * Compare the current value with the previous value + * and print only if changed. + */ } for (; cur < syscall->arg_count; ++cur) { struct syscall_argument arg = syscall->args[cur]; - OUTFI("/* arg: %s (%s) */\n", arg.name, type_to_ctype(arg.type)); - get_syscall_arg_value(arg_val, syscall, arg_index++); + OUTFI("/* arg: %s (%s) */\n", + arg.name, type_to_ctype(arg.type)); + CLEANUP_FREE char *arg_val = + get_syscall_arg_value(syscall, arg_index++); if (IS_INOUT_PTR(syscall->args[cur].type)) { - generate_printer(out, syscall, arg.name, "get_tcb_priv_data(tcp)", false, arg.type, - indent_level); + generate_printer(out, syscall, arg.name, + "get_tcb_priv_data(tcp)", + false, arg.type, indent_level); } - generate_printer(out, syscall, arg.name, arg_val, false, arg.type, - indent_level); + generate_printer(out, syscall, arg.name, arg_val, + false, arg.type, indent_level); if (cur < syscall->arg_count - 1) { OUTSI("tprint_arg_next();\n"); @@ -807,7 +835,11 @@ generate_decoder(FILE *out, struct syscall *syscall, bool is_variant, bool ioctl OUTC('\n'); } } else { - // TODO: > 1 out ptrs; store necessary ptr values using set_tcb_priv_data + /* + * TODO + * > 1 out ptrs; + * store necessary ptr values using set_tcb_priv_data + */ OUTSI("#error TODO\n"); } @@ -838,24 +870,23 @@ output_defines(FILE *out, struct preprocessor_statement_list *defines) * Outputs a function which delegates to the child syscalls based on the * values of the child's const-typed arguments. * - * The is_variant flag indicates whether the group's base syscall is a child of - * a variant syscall itself. + * The is_variant flag indicates whether the group's base syscall is a child + * of a variant syscall itself. */ void -output_variant_syscall_group(FILE *out, struct syscall_group *group, bool is_variant) +output_variant_syscall_group(FILE *out, struct syscall_group *group, + bool is_variant) { int indent_level = 0; if (is_variant) { - // variant system call - char func_name[VARIANT_FUNC_NAME_LEN]; - get_variant_function_name(func_name, group->base->name, false); - - char decoder_prototype[DECODER_PROTOTYPE_LEN]; - get_decoder_prototype(decoder_prototype, false, group->base, func_name); - + /* variant system call */ + CLEANUP_FREE char *func_name = + get_variant_function_name(group->base->name, false); + CLEANUP_FREE char *decoder_prototype = + get_decoder_prototype(false, group->base, func_name); OUTSI(decoder_prototype); } else { - // base system call + /* base system call */ OUTFI("SYS_FUNC(%s) {\n", group->base->name); } OUTSI("{\n"); @@ -871,7 +902,8 @@ output_variant_syscall_group(FILE *out, struct syscall_group *group, bool is_var OUTS("if ("); bool first = true; - for (size_t arg_idx = 0; arg_idx < cur_child->arg_count; ++arg_idx) { + for (size_t arg_idx = 0; + arg_idx < cur_child->arg_count; ++arg_idx) { struct syscall_argument arg = cur_child->args[arg_idx]; if (arg.type->type != TYPE_CONST) { @@ -884,28 +916,35 @@ output_variant_syscall_group(FILE *out, struct syscall_group *group, bool is_var OUTS(" && "); } - char arg_str[SYSCALL_ARG_STR_LEN]; - get_syscall_arg_value(arg_str, cur_child, arg_idx); - - if (arg.type->constt.value->child_type == AST_TYPE_CHILD_RANGE) { - OUTF("((%s) <= (%s) && (%s) <= (%s))", arg_str, - resolve_type_option_to_value(cur_child, arg.type->constt.value->range.min), - arg_str, - resolve_type_option_to_value(cur_child, arg.type->constt.value->range.max) + CLEANUP_FREE char *arg_str = + get_syscall_arg_value(cur_child, arg_idx); + + if (arg.type->constt.value->child_type == + AST_TYPE_CHILD_RANGE) { + OUTF("((%s) <= (%s) && (%s) <= (%s))", + arg_str, + resolve_type_option_to_value(cur_child, + arg.type->constt.value->range.min), + arg_str, + resolve_type_option_to_value(cur_child, + arg.type->constt.value->range.max) ); } else { OUTF("(%s) == (%s)", - arg_str, - resolve_type_option_to_value(cur_child, arg.type->constt.value)); + arg_str, + resolve_type_option_to_value(cur_child, + arg.type->constt.value)); } } OUTS(") {\n"); indent_level++; - char func_name[VARIANT_FUNC_NAME_LEN]; - get_variant_function_name(func_name, cur_child->name, cur_child_grp->child_count == 0); - OUTFI("return %s(tcp%s);\n", func_name, cur_child->is_ioctl ? ", code, arg" : ""); + CLEANUP_FREE char *func_name = + get_variant_function_name(cur_child->name, + cur_child_grp->child_count == 0); + OUTFI("return %s(tcp%s);\n", func_name, + cur_child->is_ioctl ? ", code, arg" : ""); indent_level--; OUTSI("} else "); @@ -914,9 +953,10 @@ output_variant_syscall_group(FILE *out, struct syscall_group *group, bool is_var OUTS("{\n"); indent_level++; - char func_name[VARIANT_FUNC_NAME_LEN]; - get_variant_function_name(func_name, group->base->name, true); - OUTFI("return %s(tcp%s);\n", func_name, group->base->is_ioctl ? ", code, arg" : ""); + CLEANUP_FREE char *func_name = + get_variant_function_name(group->base->name, true); + OUTFI("return %s(tcp%s);\n", func_name, + group->base->is_ioctl ? ", code, arg" : ""); indent_level--; OUTSI("}\n"); @@ -930,43 +970,56 @@ output_variant_syscall_group(FILE *out, struct syscall_group *group, bool is_var */ void output_syscall_groups(FILE *out, struct syscall_group *groups, - size_t group_count, struct syscall_group *parent) + size_t group_count, struct syscall_group *parent) { for (size_t i = 0; i < group_count; ++i) { struct syscall_group *cur = &groups[i]; if (parent) { - // store the real type of const parameters based on their parent - for (size_t j = 0; j < cur->base->arg_count && j < parent->base->arg_count; ++j) { - struct syscall_argument *cur_arg = &cur->base->args[j]; - struct syscall_argument *parent_arg = &parent->base->args[j]; + /* + * Store the real type of const parameters + * based on their parent. + */ + for (size_t j = 0; + j < cur->base->arg_count && j < parent->base->arg_count; + ++j) { + struct syscall_argument *cur_arg = + &cur->base->args[j]; + struct syscall_argument *parent_arg = + &parent->base->args[j]; if (cur_arg->type->type == TYPE_CONST) { if (parent_arg->type->type == TYPE_CONST) { - cur_arg->type->constt.real_type = parent_arg->type->constt.real_type; + cur_arg->type->constt.real_type = + parent_arg->type->constt.real_type; } else { - cur_arg->type->constt.real_type = parent_arg->type; + cur_arg->type->constt.real_type = + parent_arg->type; } } } } if (groups[i].child_count == 0) { - generate_decoder(out, groups[i].base, parent != NULL, false); + generate_decoder(out, groups[i].base, parent != NULL, + false); continue; } - output_syscall_groups(out, groups[i].children, groups[i].child_count, &groups[i]); + output_syscall_groups(out, groups[i].children, + groups[i].child_count, &groups[i]); if (strcmp(groups[i].base->name, "ioctl") != 0) { generate_decoder(out, groups[i].base, true, true); - output_variant_syscall_group(out, &groups[i], parent != NULL); + output_variant_syscall_group(out, &groups[i], + parent != NULL); } } } bool -generate_code(const char *in_filename, const char *out_filename, struct processed_ast *ast) +generate_code(const char *in_filename, const char *out_filename, + struct processed_ast *ast) { FILE *out = fopen(out_filename, "w"); @@ -974,7 +1027,8 @@ generate_code(const char *in_filename, const char *out_filename, struct processe return false; } - outf(out, "/* Generated by ./maint/gen/generate.sh from ./maint/gen/%s; do not edit. */\n\n", in_filename); + outf(out, "/* Generated by ./maint/gen/generate.sh" + " from ./maint/gen/%s; do not edit. */\n\n", in_filename); outf(out, "%s", "#include <stddef.h>\n" "#include \"generated.h\"\n\n" @@ -984,7 +1038,8 @@ generate_code(const char *in_filename, const char *out_filename, struct processe decoders = ast->decoders; output_defines(out, ast->preprocessor_stmts); - output_syscall_groups(out, ast->syscall_groups, ast->syscall_group_count, NULL); + output_syscall_groups(out, ast->syscall_groups, + ast->syscall_group_count, NULL); fclose(out); diff --git a/maint/gen/deflang.h b/maint/gen/deflang.h index 260b58260..6b99e9c96 100644 --- a/maint/gen/deflang.h +++ b/maint/gen/deflang.h @@ -1,29 +1,33 @@ -#include <stdbool.h> -#include <stdio.h> +/* + * Copyright (c) 2021 Srikavin Ramkumar <srikavinramkumar@gmail.com> + * Copyright (c) 2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ -#include "ast.h" -#include "preprocess.h" +#ifndef DEFLANG_H +# define DEFLANG_H + +# include <stdbool.h> +# include <stdio.h> + +# include "preprocess.h" +# include "xmalloc.h" -extern int yylineno; extern FILE *yyin; extern int last_line_location; extern char *cur_filename; -void * -xmalloc(size_t n); - -void * -xcalloc(size_t n); - -extern int -yylex_destroy(void); - bool lexer_init_newfile(char *filename); void -yyerror(const char *s, ...) __attribute__ ((format (printf, 1, 2))); +yyerror(const char *s, ...) ATTRIBUTE_FORMAT((printf, 1, 2)); bool -generate_code(const char *in_filename, const char *out_filename, struct processed_ast *ast);
\ No newline at end of file +generate_code(const char *in_filename, const char *out_filename, + struct processed_ast *ast); + +#endif /* DEFLANG_H */ diff --git a/maint/gen/defs/common.def b/maint/gen/defs/common.def index 5c1b5c396..2cffce7e6 100644 --- a/maint/gen/defs/common.def +++ b/maint/gen/defs/common.def @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2021 Srikavin Ramkumar <srikavinramkumar@gmail.com> + * Copyright (c) 2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + :fd %{ printfd(tcp, $$); %} :uid %{ printuid($$); %} :gid %{ printuid($$); %} @@ -36,7 +44,8 @@ :ptr[in, array[uint32_t, $1]] %{ { uint32_t int_buffer; - print_array(tcp, $$, $1, &int_buffer, sizeof(int_buffer), tfetch_mem, print_uint_array_member, 0); + print_array(tcp, $$, $1, &int_buffer, sizeof(int_buffer), + tfetch_mem, print_uint_array_member, 0); } %} diff --git a/maint/gen/lex.l b/maint/gen/lex.l index 3e25a6145..22baca995 100644 --- a/maint/gen/lex.l +++ b/maint/gen/lex.l @@ -1,5 +1,12 @@ -%option noyywrap yylineno nodefault warn -/* %option debug */ +/* + * Copyright (c) 2021 Srikavin Ramkumar <srikavinramkumar@gmail.com> + * Copyright (c) 2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +%option noyywrap nounput yylineno warn %{ #include <stdio.h> @@ -8,9 +15,6 @@ #include "ast.h" #include "parse.tab.h" -YYSTYPE yylval; -YYLTYPE yylloc; - static void update_yylloc(); @@ -25,9 +29,9 @@ struct saved_import_state { int last_line_location; }; -// a stack to store state before an import +/* a stack to store state before an import */ static struct saved_import_state import_states[MAX_IMPORT_LEVEL]; -// the current index into import_states +/* the current index into import_states */ static int import_level = 0; char *cur_filename; @@ -53,13 +57,13 @@ int last_line_location; ":" return T_COLON; (-)?"0x"[0-9A-Fa-f]+ { - yylval.number.raw = strdup(yytext); + yylval.number.raw = xstrdup(yytext); yylval.number.val = strtol(yytext, NULL, 16); return T_NUMBER; } (-)?[0-9]+ { - yylval.number.raw = strdup(yytext); + yylval.number.raw = xstrdup(yytext); yylval.number.val = strtol(yytext, NULL, 10); return T_NUMBER; } @@ -68,14 +72,14 @@ int last_line_location; int sign = (yytext[0] == '-') ? -1 : +1; int offset = ((sign == -1) ? sizeof("-0b") : sizeof("0b")) - 1; - // binary literals are supported in C by GNU extension - yylval.number.raw = strdup(yytext); + /* binary literals are supported in C by GNU extension */ + yylval.number.raw = xstrdup(yytext); yylval.number.val = sign * strtol(yytext + offset, NULL, 2); return T_NUMBER; } \'.\' { - yylval.number.raw = strdup(yytext); + yylval.number.raw = xstrdup(yytext); yylval.number.val = yytext[1]; return T_NUMBER; } @@ -91,31 +95,31 @@ int last_line_location; yyerror("@ can only be used in @ret"); yyterminate(); } - yylval.str = strdup(yytext); + yylval.str = xstrdup(yytext); return T_IDENTIFIER; } (?x: "%{" ( [^%] | %+ [^}] )* %* "%}" ) { - yylval.str = strdup(yytext + 2); + yylval.str = xstrdup(yytext + 2); yylval.str[strlen(yylval.str) - 2] ='\0'; return T_DECODER_SOURCE; } "define".+ { - yylval.str = strdup(yytext); + yylval.str = xstrdup(yytext); return T_DEFINE; } "#ifdef".+ { - yylval.str = strdup(yytext); + yylval.str = xstrdup(yytext); return T_IFDEF; } "#ifndef".+ { - yylval.str = strdup(yytext); + yylval.str = xstrdup(yytext); return T_IFNDEF; } "include".+ { - yylval.str = strdup(yytext); + yylval.str = xstrdup(yytext); return T_INCLUDE; } "#endif".* { @@ -127,23 +131,24 @@ int last_line_location; } <IMPORT>[^\n\"]+ { if (import_level >= MAX_IMPORT_LEVEL) { - fprintf(stderr, "imports are nested more than %d levels\n", MAX_IMPORT_LEVEL); + fprintf(stderr, "imports are nested more than %d levels\n", + MAX_IMPORT_LEVEL); yyterminate(); } - // eat characters until newline + /* eat characters until newline */ int c = input(); cur_location++; while(c && c != '\n'){ cur_location++; c = input(); } - // update current location + /* update current location */ yylloc.last_line++; yylloc.last_column = 1; last_line_location = cur_location; - // save current state + /* save current state */ import_states[import_level++] = (struct saved_import_state) { .filename = cur_filename, .location = yylloc, @@ -151,7 +156,7 @@ int last_line_location; .last_line_location = last_line_location }; - cur_filename = strdup(yytext); + cur_filename = xstrdup(yytext); yylloc = (struct YYLTYPE) {1, 1, 1, 1}; cur_location = 0; @@ -160,7 +165,8 @@ int last_line_location; yyin = fopen(yytext, "r"); if (yyin == NULL) { - fprintf(stderr, "failed to import file '%s' on line %d\n", yytext, yylineno); + fprintf(stderr, "failed to import file '%s' on line %d\n", + yytext, yylineno); yyterminate(); } @@ -169,8 +175,10 @@ int last_line_location; } <<EOF>> { - // emit a newline at the end of a file before EOF - // to ensure the last statement in the file is terminated + /* + * Emit a newline at the end of a file before EOF + * to ensure the last statement in the file is terminated. + */ static int emitted_newline; if (!emitted_newline) { @@ -248,7 +256,7 @@ update_yylloc() bool lexer_init_newfile(char *filename) { - // clean up internal state managed by flex + /* clean up internal state managed by flex */ yylex_destroy(); yyin = fopen(filename, "r"); diff --git a/maint/gen/parse.y b/maint/gen/parse.y index 23b773153..11e0830aa 100644 --- a/maint/gen/parse.y +++ b/maint/gen/parse.y @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2021 Srikavin Ramkumar <srikavinramkumar@gmail.com> + * Copyright (c) 2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + %define api.token.prefix {T_} %define parse.lac full %define parse.error detailed @@ -20,6 +28,8 @@ static struct ast_node *root; static void error_prev_decl(char *identifier, struct ast_node *prev); + +int yylex(void); %} %union { @@ -317,49 +327,53 @@ flag_elements: IDENTIFIER "," flag_elements static void error_prev_decl(char *identifier, struct ast_node *prev) { - yyerror("Previous declaration of %s at line %d col %d", identifier, - prev->loc.lineno, prev->loc.colno); + yyerror("Previous declaration of %s at line %d col %d", + identifier, prev->loc.lineno, prev->loc.colno); } void -yyerror (const char* fmt, ...) +yyerror(const char* fmt, ...) { - char buffer[257] = {0}; - - if (yyin == NULL) { - return; - } - - long int saved = ftell(yyin); - fseek(yyin, last_line_location, SEEK_SET); - fgets(buffer, 256, yyin); - fseek(yyin, saved, SEEK_SET); - - // add a new line if necessary - size_t len = strlen(buffer); - if (len > 0 && buffer[len - 1] != '\n') { - buffer[len] = '\n'; - buffer[len + 1] = '\0'; + fprintf(stderr, "error %d: %s: line %d column %d\n", + yynerrs, cur_filename, yylloc.first_line, yylloc.first_column); + if (yyin) { + char buffer[257]; + long int saved = ftell(yyin); + if (saved == -1 || + fseek(yyin, last_line_location, SEEK_SET) != 0 || + fgets(buffer, sizeof(buffer) - 1, yyin) == NULL) { + buffer[0] = '\0'; + } + if (saved != -1) { + fseek(yyin, saved, SEEK_SET); + } + + /* add a new line if necessary */ + size_t len = strlen(buffer); + if (len > 0) { + if (buffer[len - 1] != '\n') { + buffer[len] = '\n'; + buffer[len + 1] = '\0'; + } + fprintf(stderr, "\t%s", buffer); + } } + fprintf(stderr, "\t%*s ", yylloc.first_column, "^"); va_list args; va_start(args, fmt); - - fprintf(stderr, "error %d: %s: line %d column %d\n", yynerrs, cur_filename, - yylloc.first_line, yylloc.first_column); - fprintf(stderr, "\t%s", buffer); - fprintf(stderr, "\t%*s ", yylloc.first_column, "^"); vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - va_end(args); + + fprintf(stderr, "\n"); } int main(int argc, char **argv) { if (argc < 3) { - fprintf(stderr, "Usage: %s [input file] [output file]\n", argv[0]); + fprintf(stderr, "Usage: %s [input file] [output file]\n", + argv[0]); return EXIT_FAILURE; } diff --git a/maint/gen/preprocess.c b/maint/gen/preprocess.c index 333b56293..211b49a63 100644 --- a/maint/gen/preprocess.c +++ b/maint/gen/preprocess.c @@ -1,14 +1,19 @@ +/* + * Copyright (c) 2021 Srikavin Ramkumar <srikavinramkumar@gmail.com> + * Copyright (c) 2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + #include <assert.h> #include <ctype.h> -#include <memory.h> -#include <stddef.h> #include <stdlib.h> #include <string.h> #include "ast.h" #include "deflang.h" #include "symbols.h" -#include "printf.h" #define MAX_PREPROCESSOR_NEST 16 #define MAX_SYSCALL_COUNT 4096 @@ -31,7 +36,8 @@ create_statement_condition(struct condition_stack *stack) if (stack->idx == 0) { return NULL; } - struct statement_condition *ret = xmalloc((sizeof *ret) + stack->idx * (sizeof(char *))); + struct statement_condition *ret = + xmalloc((sizeof *ret) + stack->idx * (sizeof(char *))); ret->count = stack->idx; memcpy(ret->values, stack->stack, stack->idx * (sizeof(char *))); return ret; @@ -121,7 +127,8 @@ preprocess_rec(struct ast_node *root, struct condition_stack *cur, arg_count++; } - struct syscall *new = xmalloc(sizeof(*new) + sizeof(struct syscall_argument) * arg_count); + struct syscall *new = + xmalloc(sizeof(*new) + sizeof(struct syscall_argument) * arg_count); *new = (struct syscall) { .name = root->syscall.name, .conditions = create_statement_condition(cur), @@ -156,7 +163,7 @@ preprocess_rec(struct ast_node *root, struct condition_stack *cur, */ static size_t find_matching(struct syscall **syscall_buffer, size_t syscall_count, - struct syscall_group *out) + struct syscall_group *out) { struct syscall *base = syscall_buffer[0]; assert(base != NULL); @@ -165,11 +172,11 @@ find_matching(struct syscall **syscall_buffer, size_t syscall_count, size_t matching = 0; for (size_t i = 1; i < syscall_count; i++) { struct syscall *cur = syscall_buffer[i]; - // all variants start with the same name as the base + /* all variants start with the same name as the base */ if (strncmp(cur->name, base->name, base_name_len) != 0) { break; } - // and their last '$' is immediately after the base name + /* and their last '$' is immediately after the base name */ char *last_dollar = strrchr(cur->name, '$'); if (last_dollar == cur->name + base_name_len) { matching++; @@ -185,7 +192,8 @@ find_matching(struct syscall **syscall_buffer, size_t syscall_count, return 1; } - struct syscall_group *children = xmalloc(sizeof(struct syscall_group) * matching); + struct syscall_group *children = + xmalloc(sizeof(struct syscall_group) * matching); size_t children_idx = 0; size_t i = 1; @@ -196,13 +204,14 @@ find_matching(struct syscall **syscall_buffer, size_t syscall_count, } char *last_dollar = strrchr(cur->name, '$'); if (last_dollar != cur->name + base_name_len) { - // not a direct subvariant - fprintf(stderr, "not subvariant %s -> %s \n", base->name, cur->name); + /* not a direct subvariant */ + fprintf(stderr, "not subvariant %s -> %s \n", + base->name, cur->name); i += 1; continue; } i += find_matching(syscall_buffer + i, syscall_count - i, - children + children_idx); + children + children_idx); children_idx++; } @@ -228,29 +237,40 @@ syscall_comparator(const void *a, const void *b) static struct syscall_group * group_syscall_variants(struct processing_state *state, size_t *out_count) { - // The idea is to sort the syscalls by name: - // "prctl" "prctl$GET_FP_MODE" - // "prctl$PR_CAP_AMBIENT" "prctl$PR_CAP_AMBIENT$PR_CAP_AMBIENT_LOWER" - // This way, every variant will immediately follow the base syscall and will - // be grouped into a syscall_group 'find_matching'. + /* + * The idea is to sort the syscalls by name: + * "prctl" "prctl$GET_FP_MODE" + * "prctl$PR_CAP_AMBIENT" + * "prctl$PR_CAP_AMBIENT$PR_CAP_AMBIENT_LOWER" + * This way, every variant will immediately follow the base syscall + * and will be grouped into a syscall_group 'find_matching'. + */ qsort(state->syscall_buffer, state->syscall_index, - sizeof(struct syscall *), syscall_comparator); + sizeof(struct syscall *), syscall_comparator); - // in the worst case (no variants), there can be MAX_SYSCALL_COUNT syscall groups - struct syscall_group *scratch = xcalloc(sizeof(*scratch) * MAX_SYSCALL_COUNT); + /* + * In the worst case (no variants), + * there can be MAX_SYSCALL_COUNT syscall groups. + */ + struct syscall_group *scratch = + xcalloc(MAX_SYSCALL_COUNT, sizeof(*scratch)); size_t groups = 0; size_t i = 0; while (i < state->syscall_index) { - i += find_matching(state->syscall_buffer + i, state->syscall_index - i, scratch + groups); + i += find_matching(state->syscall_buffer + i, + state->syscall_index - i, + scratch + groups); groups++; } - struct syscall_group *ret = realloc(scratch, sizeof(*scratch) * (groups + 1)); + struct syscall_group *ret = + realloc(scratch, sizeof(*scratch) * (groups + 1)); if (ret == NULL) { - fprintf(stderr, "realloc failed for %zu bytes\n", sizeof(*scratch) * groups); + fprintf(stderr, "realloc failed for %zu bytes\n", + sizeof(*scratch) * groups); exit(1); } @@ -264,7 +284,8 @@ preprocess(struct ast_node *root) struct processed_ast *ret = xmalloc(sizeof *ret); struct processing_state state = (struct processing_state) { - .syscall_buffer = xcalloc(sizeof(struct syscall *) * MAX_SYSCALL_COUNT), + .syscall_buffer = + xcalloc(MAX_SYSCALL_COUNT, sizeof(struct syscall *)), .syscall_index = 0, .struct_stmts = NULL, .preprocessor_head = NULL, @@ -277,7 +298,8 @@ preprocess(struct ast_node *root) ret->preprocessor_stmts = state.preprocessor_head; ret->struct_stmts = state.struct_stmts; - ret->syscall_groups = group_syscall_variants(&state, &ret->syscall_group_count); + ret->syscall_groups = + group_syscall_variants(&state, &ret->syscall_group_count); ret->decoders = state.decoder_head; return ret; diff --git a/maint/gen/preprocess.h b/maint/gen/preprocess.h index 31bda8658..1a96f80fa 100644 --- a/maint/gen/preprocess.h +++ b/maint/gen/preprocess.h @@ -1,5 +1,15 @@ +/* + * Copyright (c) 2021 Srikavin Ramkumar <srikavinramkumar@gmail.com> + * Copyright (c) 2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + #ifndef PREPROCESS_H -#define PREPROCESS_H +# define PREPROCESS_H + +# include "ast.h" /* * Stores nested #ifdef/#ifndef statements sequentially (as a stack) @@ -22,7 +32,7 @@ struct statement_condition { struct preprocessor_statement { struct ast_loc loc; - // can be NULL + /* can be NULL */ struct statement_condition *conditions; char *value; @@ -38,7 +48,7 @@ struct struct_def { char *name; struct statement_condition *conditions; - // TODO + /* TODO */ }; struct syscall_argument { @@ -49,13 +59,15 @@ struct syscall_argument { struct decoder { struct ast_loc loc; - // the type this decoder handles + /* the type this decoder handles */ struct ast_type *matching_type; - // a format string containing C source code of a decoder capable of handling - // arguments/return values of type 'matching_type'. - // the first printf arg is a variable containing the value of the argument. - // the second printf arg is the index of the argument. + /* + * A format string containing C source code of a decoder + * capable of handling arguments/return values of type 'matching_type'. + * The first printf arg is a variable containing the value of the + * argument, the second printf arg is the index of the argument. + */ char *fmt_string; }; @@ -67,18 +79,18 @@ struct decoder_list { struct syscall { struct ast_loc loc; - // can be NULL + /* can be NULL */ struct statement_condition *conditions; - // name of the syscall + /* name of the syscall */ char *name; bool is_ioctl; - // the return value of the syscall + /* the return value of the syscall */ struct ast_type ret; - // the defined arguments + /* the defined arguments */ size_t arg_count; struct syscall_argument args[]; }; diff --git a/maint/gen/symbols.c b/maint/gen/symbols.c index bf4e1d3a0..076e29fcb 100644 --- a/maint/gen/symbols.c +++ b/maint/gen/symbols.c @@ -24,7 +24,8 @@ struct symbol_entry *symbol_table; struct ast_node * symbol_get(char *name) { - for (struct symbol_entry *cur = symbol_table; cur != NULL; cur = cur->next) { + for (struct symbol_entry *cur = symbol_table; + cur != NULL; cur = cur->next) { if (strcmp(cur->name, name) == 0) { return cur->source; } @@ -55,7 +56,8 @@ symbol_add(char *name, struct ast_node *source) char * -resolve_type(struct ast_type *out, char *name, struct ast_type_option_list *options) +resolve_type(struct ast_type *out, char *name, + struct ast_type_option_list *options) { out->name = name; out->options = options; @@ -73,7 +75,8 @@ resolve_type(struct ast_type *out, char *name, struct ast_type_option_list *opti }; size_t options_len = 0; - for (struct ast_type_option_list *cur = options; cur != NULL; cur = cur->next) { + for (struct ast_type_option_list *cur = options; + cur != NULL; cur = cur->next) { if (cur->option->child_type == AST_TYPE_CHILD_TEMPLATE_ID) { return NULL; } @@ -84,10 +87,11 @@ resolve_type(struct ast_type *out, char *name, struct ast_type_option_list *opti for (size_t i = 0; i < ARRAY_LEN(expected_options_len); ++i) { if (strcmp(name, expected_options_len[i].name) == 0) { if (options_len != expected_options_len[i].expected_args) { - char *error = xmalloc(128); - snprintf(error, 128, "type '%s' expects %zu type options; got %zu", - name, expected_options_len[i].expected_args, options_len); - return error; + return xasprintf("type '%s' expects %zu " + "type options; got %zu", + name, + expected_options_len[i].expected_args, + options_len); } } } @@ -99,7 +103,8 @@ resolve_type(struct ast_type *out, char *name, struct ast_type_option_list *opti } else if (strcmp(name, "ptr") == 0) { out->type = TYPE_PTR; if (options->option->child_type != AST_TYPE_CHILD_TYPE) { - return "first type option for ptr must be 'in', 'out' or 'inout'"; + return "first type option for ptr must be" + " 'in', 'out' or 'inout'"; } if (strcmp(options->option->type->name, "in") == 0) { out->ptr.dir = PTR_DIR_IN; @@ -108,13 +113,15 @@ resolve_type(struct ast_type *out, char *name, struct ast_type_option_list *opti } else if (strcmp(options->option->type->name, "inout") == 0) { out->ptr.dir = PTR_DIR_INOUT; } else { - return "first type option for ptr must be 'in', 'out' or 'inout'"; + return "first type option for ptr must be" + " 'in', 'out' or 'inout'"; } out->ptr.type = options->next->option->type; } else if (strcmp(name, "ref") == 0) { out->type = TYPE_REF; if (options->option->child_type != AST_TYPE_CHILD_TYPE) { - return "first type option for len must be the name of another argument or $ret"; + return "first type option for len must be" + " the name of another argument or $ret"; } if (strcmp(options->option->type->name, "@ret") == 0) { out->ref.return_value = true; @@ -129,8 +136,10 @@ resolve_type(struct ast_type *out, char *name, struct ast_type_option_list *opti return "first type option for ptr must be a string"; } out->xorflags.dflt = options->next->option->type->name; - if (options->next->next->option->child_type != AST_TYPE_CHILD_TYPE) { - return "third type option for xor_flags must be the underlying flag type"; + if (options->next->next->option->child_type != + AST_TYPE_CHILD_TYPE) { + return "third type option for xor_flags must be" + " the underlying flag type"; } out->xorflags.underlying = options->next->next->option->type; } else if (strcmp(name, "or_flags") == 0) { @@ -140,8 +149,10 @@ resolve_type(struct ast_type *out, char *name, struct ast_type_option_list *opti return "first type option for ptr must be a string"; } out->orflags.dflt = options->next->option->type->name; - if (options->next->next->option->child_type != AST_TYPE_CHILD_TYPE) { - return "third type option for or_flags must be the underlying flag type"; + if (options->next->next->option->child_type != + AST_TYPE_CHILD_TYPE) { + return "third type option for or_flags must be" + " the underlying flag type"; } out->orflags.underlying = options->next->next->option->type; } diff --git a/maint/gen/symbols.h b/maint/gen/symbols.h index 1737ddccf..1c2e8d47f 100644 --- a/maint/gen/symbols.h +++ b/maint/gen/symbols.h @@ -7,11 +7,9 @@ */ #ifndef SYMBOLS_H -#define SYMBOLS_H +# define SYMBOLS_H -#include <stdbool.h> - -#include "ast.h" +# include "ast.h" /* * Returns a error string if the given type is @@ -19,7 +17,8 @@ * valid. */ char * -resolve_type(struct ast_type *out, char *name, struct ast_type_option_list *options); +resolve_type(struct ast_type *out, char *name, + struct ast_type_option_list *options); /* * Returns NULL if successfully added a symbol. diff --git a/maint/gen/xmalloc.c b/maint/gen/xmalloc.c new file mode 100644 index 000000000..f3718a5ba --- /dev/null +++ b/maint/gen/xmalloc.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015 Dmitry V. Levin <ldv@strace.io> + * Copyright (c) 2015-2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "xmalloc.h" + +static void +die_out_of_memory(void) +{ + fprintf(stderr, "allocation failed\n"); + exit(EXIT_FAILURE); +} + +void +free_by_pointer(void *p) { + void **pp = (void **) p; + free(*pp); + *pp = NULL; +} + +void * +xmalloc(size_t n) +{ + void *p = malloc(n); + + if (!p) + die_out_of_memory(); + + return p; +} + +void * +xcalloc(size_t nmemb, size_t size) +{ + void *p = calloc(nmemb, size); + + if (!p) + die_out_of_memory(); + + return p; +} + +char * +xstrdup(const char *str) +{ + if (!str) + return NULL; + + char *p = strdup(str); + + if (!p) + die_out_of_memory(); + + return p; +} + +char * +xasprintf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + char *res; + if (vasprintf(&res, fmt, ap) < 0) + die_out_of_memory(); + + va_end(ap); + return res; +} diff --git a/maint/gen/xmalloc.h b/maint/gen/xmalloc.h new file mode 100644 index 000000000..61b48ffda --- /dev/null +++ b/maint/gen/xmalloc.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015 Dmitry V. Levin <ldv@strace.io> + * Copyright (c) 2015-2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef XMALLOC_H +# define XMALLOC_H + +# define ATTRIBUTE_FORMAT(args) __attribute__((__format__ args)) +# define ATTRIBUTE_MALLOC __attribute__((__malloc__)) +# define ATTRIBUTE_ALLOC_SIZE(args) __attribute__((__alloc_size__ args)) +# define ATTRIBUTE_CLEANUP(args) __attribute__((__cleanup__(args))) + +# define CLEANUP_FREE ATTRIBUTE_CLEANUP(free_by_pointer) + +void +free_by_pointer(void *); + +void * +xmalloc(size_t) + ATTRIBUTE_MALLOC ATTRIBUTE_ALLOC_SIZE((1)); + +void * +xcalloc(size_t nmemb, size_t size) + ATTRIBUTE_MALLOC ATTRIBUTE_ALLOC_SIZE((1, 2)); + +char * +xstrdup(const char *); + +char *xasprintf(const char *fmt, ...) + ATTRIBUTE_FORMAT((printf, 1, 2)) ATTRIBUTE_MALLOC; + +#endif /* XMALLOC_H */ |