cregit-Linux how code gets into the kernel

Release 4.10 scripts/asn1_compiler.c

Directory: scripts
/* Simplified ASN.1 notation parser
 *
 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public Licence
 * as published by the Free Software Foundation; either version
 * 2 of the Licence, or (at your option) any later version.
 */

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <linux/asn1_ber_bytecode.h>


enum token_type {
	
DIRECTIVE_ABSENT,
	
DIRECTIVE_ALL,
	
DIRECTIVE_ANY,
	
DIRECTIVE_APPLICATION,
	
DIRECTIVE_AUTOMATIC,
	
DIRECTIVE_BEGIN,
	
DIRECTIVE_BIT,
	
DIRECTIVE_BMPString,
	
DIRECTIVE_BOOLEAN,
	
DIRECTIVE_BY,
	
DIRECTIVE_CHARACTER,
	
DIRECTIVE_CHOICE,
	
DIRECTIVE_CLASS,
	
DIRECTIVE_COMPONENT,
	
DIRECTIVE_COMPONENTS,
	
DIRECTIVE_CONSTRAINED,
	
DIRECTIVE_CONTAINING,
	
DIRECTIVE_DEFAULT,
	
DIRECTIVE_DEFINED,
	
DIRECTIVE_DEFINITIONS,
	
DIRECTIVE_EMBEDDED,
	
DIRECTIVE_ENCODED,
	
DIRECTIVE_ENCODING_CONTROL,
	
DIRECTIVE_END,
	
DIRECTIVE_ENUMERATED,
	
DIRECTIVE_EXCEPT,
	
DIRECTIVE_EXPLICIT,
	
DIRECTIVE_EXPORTS,
	
DIRECTIVE_EXTENSIBILITY,
	
DIRECTIVE_EXTERNAL,
	
DIRECTIVE_FALSE,
	
DIRECTIVE_FROM,
	
DIRECTIVE_GeneralString,
	
DIRECTIVE_GeneralizedTime,
	
DIRECTIVE_GraphicString,
	
DIRECTIVE_IA5String,
	
DIRECTIVE_IDENTIFIER,
	
DIRECTIVE_IMPLICIT,
	
DIRECTIVE_IMPLIED,
	
DIRECTIVE_IMPORTS,
	
DIRECTIVE_INCLUDES,
	
DIRECTIVE_INSTANCE,
	
DIRECTIVE_INSTRUCTIONS,
	
DIRECTIVE_INTEGER,
	
DIRECTIVE_INTERSECTION,
	
DIRECTIVE_ISO646String,
	
DIRECTIVE_MAX,
	
DIRECTIVE_MIN,
	
DIRECTIVE_MINUS_INFINITY,
	
DIRECTIVE_NULL,
	
DIRECTIVE_NumericString,
	
DIRECTIVE_OBJECT,
	
DIRECTIVE_OCTET,
	
DIRECTIVE_OF,
	
DIRECTIVE_OPTIONAL,
	
DIRECTIVE_ObjectDescriptor,
	
DIRECTIVE_PATTERN,
	
DIRECTIVE_PDV,
	
DIRECTIVE_PLUS_INFINITY,
	
DIRECTIVE_PRESENT,
	
DIRECTIVE_PRIVATE,
	
DIRECTIVE_PrintableString,
	
DIRECTIVE_REAL,
	
DIRECTIVE_RELATIVE_OID,
	
DIRECTIVE_SEQUENCE,
	
DIRECTIVE_SET,
	
DIRECTIVE_SIZE,
	
DIRECTIVE_STRING,
	
DIRECTIVE_SYNTAX,
	
DIRECTIVE_T61String,
	
DIRECTIVE_TAGS,
	
DIRECTIVE_TRUE,
	
DIRECTIVE_TeletexString,
	
DIRECTIVE_UNION,
	
DIRECTIVE_UNIQUE,
	
DIRECTIVE_UNIVERSAL,
	
DIRECTIVE_UTCTime,
	
DIRECTIVE_UTF8String,
	
DIRECTIVE_UniversalString,
	
DIRECTIVE_VideotexString,
	
DIRECTIVE_VisibleString,
	
DIRECTIVE_WITH,
	
NR__DIRECTIVES,
	
TOKEN_ASSIGNMENT = NR__DIRECTIVES,
	
TOKEN_OPEN_CURLY,
	
TOKEN_CLOSE_CURLY,
	
TOKEN_OPEN_SQUARE,
	
TOKEN_CLOSE_SQUARE,
	
TOKEN_OPEN_ACTION,
	
TOKEN_CLOSE_ACTION,
	
TOKEN_COMMA,
	
TOKEN_NUMBER,
	
TOKEN_TYPE_NAME,
	
TOKEN_ELEMENT_NAME,
	
NR__TOKENS
};


static const unsigned char token_to_tag[NR__TOKENS] = {
	/* EOC goes first */
	[DIRECTIVE_BOOLEAN]		= ASN1_BOOL,
	[DIRECTIVE_INTEGER]		= ASN1_INT,
	[DIRECTIVE_BIT]			= ASN1_BTS,
	[DIRECTIVE_OCTET]		= ASN1_OTS,
	[DIRECTIVE_NULL]		= ASN1_NULL,
	[DIRECTIVE_OBJECT]		= ASN1_OID,
	[DIRECTIVE_ObjectDescriptor]	= ASN1_ODE,
	[DIRECTIVE_EXTERNAL]		= ASN1_EXT,
	[DIRECTIVE_REAL]		= ASN1_REAL,
	[DIRECTIVE_ENUMERATED]		= ASN1_ENUM,
	[DIRECTIVE_EMBEDDED]		= 0,
	[DIRECTIVE_UTF8String]		= ASN1_UTF8STR,
	[DIRECTIVE_RELATIVE_OID]	= ASN1_RELOID,
	/* 14 */
	/* 15 */
	[DIRECTIVE_SEQUENCE]		= ASN1_SEQ,
	[DIRECTIVE_SET]			= ASN1_SET,
	[DIRECTIVE_NumericString]	= ASN1_NUMSTR,
	[DIRECTIVE_PrintableString]	= ASN1_PRNSTR,
	[DIRECTIVE_T61String]		= ASN1_TEXSTR,
	[DIRECTIVE_TeletexString]	= ASN1_TEXSTR,
	[DIRECTIVE_VideotexString]	= ASN1_VIDSTR,
	[DIRECTIVE_IA5String]		= ASN1_IA5STR,
	[DIRECTIVE_UTCTime]		= ASN1_UNITIM,
	[DIRECTIVE_GeneralizedTime]	= ASN1_GENTIM,
	[DIRECTIVE_GraphicString]	= ASN1_GRASTR,
	[DIRECTIVE_VisibleString]	= ASN1_VISSTR,
	[DIRECTIVE_GeneralString]	= ASN1_GENSTR,
	[DIRECTIVE_UniversalString]	= ASN1_UNITIM,
	[DIRECTIVE_CHARACTER]		= ASN1_CHRSTR,
	[DIRECTIVE_BMPString]		= ASN1_BMPSTR,
};


static const char asn1_classes[4][5] = {
	[ASN1_UNIV]	= "UNIV",
	[ASN1_APPL]	= "APPL",
	[ASN1_CONT]	= "CONT",
	[ASN1_PRIV]	= "PRIV"
};


static const char asn1_methods[2][5] = {
	[ASN1_UNIV]	= "PRIM",
	[ASN1_APPL]	= "CONS"
};


static const char *const asn1_universal_tags[32] = {
	"EOC",
	"BOOL",
	"INT",
	"BTS",
	"OTS",
	"NULL",
	"OID",
	"ODE",
	"EXT",
	"REAL",
	"ENUM",
	"EPDV",
	"UTF8STR",
	"RELOID",
	NULL,		/* 14 */
	NULL,		/* 15 */
	"SEQ",
	"SET",
	"NUMSTR",
	"PRNSTR",
	"TEXSTR",
	"VIDSTR",
	"IA5STR",
	"UNITIM",
	"GENTIM",
	"GRASTR",
	"VISSTR",
	"GENSTR",
	"UNISTR",
	"CHRSTR",
	"BMPSTR",
	NULL		/* 31 */
};


static const char *filename;

static const char *grammar_name;

static const char *outputname;

static const char *headername;


static const char *const directives[NR__DIRECTIVES] = {

#define _(X) [DIRECTIVE_##X] = #X
	_(ABSENT),
	_(ALL),
	_(ANY),
	_(APPLICATION),
	_(AUTOMATIC),
	_(BEGIN),
	_(BIT),
	_(BMPString),
	_(BOOLEAN),
	_(BY),
	_(CHARACTER),
	_(CHOICE),
	_(CLASS),
	_(COMPONENT),
	_(COMPONENTS),
	_(CONSTRAINED),
	_(CONTAINING),
	_(DEFAULT),
	_(DEFINED),
	_(DEFINITIONS),
	_(EMBEDDED),
	_(ENCODED),
	[DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
	_(END),
	_(ENUMERATED),
	_(EXCEPT),
	_(EXPLICIT),
	_(EXPORTS),
	_(EXTENSIBILITY),
	_(EXTERNAL),
	_(FALSE),
	_(FROM),
	_(GeneralString),
	_(GeneralizedTime),
	_(GraphicString),
	_(IA5String),
	_(IDENTIFIER),
	_(IMPLICIT),
	_(IMPLIED),
	_(IMPORTS),
	_(INCLUDES),
	_(INSTANCE),
	_(INSTRUCTIONS),
	_(INTEGER),
	_(INTERSECTION),
	_(ISO646String),
	_(MAX),
	_(MIN),
	[DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
	[DIRECTIVE_NULL] = "NULL",
	_(NumericString),
	_(OBJECT),
	_(OCTET),
	_(OF),
	_(OPTIONAL),
	_(ObjectDescriptor),
	_(PATTERN),
	_(PDV),
	[DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
	_(PRESENT),
	_(PRIVATE),
	_(PrintableString),
	_(REAL),
	[DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
	_(SEQUENCE),
	_(SET),
	_(SIZE),
	_(STRING),
	_(SYNTAX),
	_(T61String),
	_(TAGS),
	_(TRUE),
	_(TeletexString),
	_(UNION),
	_(UNIQUE),
	_(UNIVERSAL),
	_(UTCTime),
	_(UTF8String),
	_(UniversalString),
	_(VideotexString),
	_(VisibleString),
	_(WITH)
};


struct action {
	
struct action	*next;
	
char		*name;
	
unsigned char	index;
};


static struct action *action_list;

static unsigned nr_actions;


struct token {
	
unsigned short	line;
	
enum token_type	token_type : 8;
	
unsigned char	size;
	
struct action	*action;
	
char		*content;
	
struct type	*type;
};


static struct token *token_list;

static unsigned nr_tokens;

static bool verbose_opt;

static bool debug_opt;


#define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)

#define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)


static int directive_compare(const void *_key, const void *_pdir) { const struct token *token = _key; const char *const *pdir = _pdir, *dir = *pdir; size_t dlen, clen; int val; dlen = strlen(dir); clen = (dlen < token->size) ? dlen : token->size; //debug("cmp(%s,%s) = ", token->content, dir); val = memcmp(token->content, dir, clen); if (val != 0) { //debug("%d [cmp]\n", val); return val; } if (dlen == token->size) { //debug("0\n"); return 0; } //debug("%d\n", (int)dlen - (int)token->size); return dlen - token->size; /* shorter -> negative */ }

Contributors

PersonTokensPropCommitsCommitProp
david howellsdavid howells11697.48%266.67%
arnd bergmannarnd bergmann32.52%133.33%
Total119100.00%3100.00%

/* * Tokenise an ASN.1 grammar */
static void tokenise(char *buffer, char *end) { struct token *tokens; char *line, *nl, *start, *p, *q; unsigned tix, lineno; /* Assume we're going to have half as many tokens as we have * characters */ token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token)); if (!tokens) { perror(NULL); exit(1); } tix = 0; lineno = 0; while (buffer < end) { /* First of all, break out a line */ lineno++; line = buffer; nl = memchr(line, '\n', end - buffer); if (!nl) { buffer = nl = end; } else { buffer = nl + 1; *nl = '\0'; } /* Remove "--" comments */ p = line; next_comment: while ((p = memchr(p, '-', nl - p))) { if (p[1] == '-') { /* Found a comment; see if there's a terminator */ q = p + 2; while ((q = memchr(q, '-', nl - q))) { if (q[1] == '-') { /* There is - excise the comment */ q += 2; memmove(p, q, nl - q); goto next_comment; } q++; } *p = '\0'; nl = p; break; } else { p++; } } p = line; while (p < nl) { /* Skip white space */ while (p < nl && isspace(*p)) *(p++) = 0; if (p >= nl) break; tokens[tix].line = lineno; start = p; /* Handle string tokens */ if (isalpha(*p)) { const char **dir, *start = p; /* Can be a directive, type name or element * name. Find the end of the name. */ q = p + 1; while (q < nl && (isalnum(*q) || *q == '-' || *q == '_')) q++; tokens[tix].size = q - p; p = q; tokens[tix].content = malloc(tokens[tix].size + 1); if (!tokens[tix].content) { perror(NULL); exit(1); } memcpy(tokens[tix].content, start, tokens[tix].size); tokens[tix].content[tokens[tix].size] = 0; /* If it begins with a lowercase letter then * it's an element name */ if (islower(tokens[tix].content[0])) { tokens[tix++].token_type = TOKEN_ELEMENT_NAME; continue; } /* Otherwise we need to search the directive * table */ dir = bsearch(&tokens[tix], directives, sizeof(directives) / sizeof(directives[1]), sizeof(directives[1]), directive_compare); if (dir) { tokens[tix++].token_type = dir - directives; continue; } tokens[tix++].token_type = TOKEN_TYPE_NAME; continue; } /* Handle numbers */ if (isdigit(*p)) { /* Find the end of the number */ q = p + 1; while (q < nl && (isdigit(*q))) q++; tokens[tix].size = q - p; p = q; tokens[tix].content = malloc(tokens[tix].size + 1); if (!tokens[tix].content) { perror(NULL); exit(1); } memcpy(tokens[tix].content, start, tokens[tix].size); tokens[tix].content[tokens[tix].size] = 0; tokens[tix++].token_type = TOKEN_NUMBER; continue; } if (nl - p >= 3) { if (memcmp(p, "::=", 3) == 0) { p += 3; tokens[tix].size = 3; tokens[tix].content = "::="; tokens[tix++].token_type = TOKEN_ASSIGNMENT; continue; } } if (nl - p >= 2) { if (memcmp(p, "({", 2) == 0) { p += 2; tokens[tix].size = 2; tokens[tix].content = "({"; tokens[tix++].token_type = TOKEN_OPEN_ACTION; continue; } if (memcmp(p, "})", 2) == 0) { p += 2; tokens[tix].size = 2; tokens[tix].content = "})"; tokens[tix++].token_type = TOKEN_CLOSE_ACTION; continue; } } if (nl - p >= 1) { tokens[tix].size = 1; switch (*p) { case '{': p += 1; tokens[tix].content = "{"; tokens[tix++].token_type = TOKEN_OPEN_CURLY; continue; case '}': p += 1; tokens[tix].content = "}"; tokens[tix++].token_type = TOKEN_CLOSE_CURLY; continue; case '[': p += 1; tokens[tix].content = "["; tokens[tix++].token_type = TOKEN_OPEN_SQUARE; continue; case ']': p += 1; tokens[tix].content = "]"; tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; continue; case ',': p += 1; tokens[tix].content = ","; tokens[tix++].token_type = TOKEN_COMMA; continue; default: break; } } fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n", filename, lineno, *p); exit(1); } } nr_tokens = tix; verbose("Extracted %u tokens\n", nr_tokens); #if 0 { int n; for (n = 0; n < nr_tokens; n++) debug("Token %3u: '%s'\n", n, token_list[n].content); } #endif }

Contributors

PersonTokensPropCommitsCommitProp
david howellsdavid howells1053100.00%3100.00%
Total1053100.00%3100.00%

static void build_type_list(void); static void parse(void); static void dump_elements(void); static void render(FILE *out, FILE *hdr); /* * */
int main(int argc, char **argv) { struct stat st; ssize_t readlen; FILE *out, *hdr; char *buffer, *p; char *kbuild_verbose; int fd; kbuild_verbose = getenv("KBUILD_VERBOSE"); if (kbuild_verbose) verbose_opt = atoi(kbuild_verbose); while (argc > 4) { if (strcmp(argv[1], "-v") == 0) verbose_opt = true; else if (strcmp(argv[1], "-d") == 0) debug_opt = true; else break; memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *)); argc--; } if (argc != 4) { fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n", argv[0]); exit(2); } filename = argv[1]; outputname = argv[2]; headername = argv[3]; fd = open(filename, O_RDONLY); if (fd < 0) { perror(filename); exit(1); } if (fstat(fd, &st) < 0) { perror(filename); exit(1); } if (!(buffer = malloc(st.st_size + 1))) { perror(NULL); exit(1); } if ((readlen = read(fd, buffer, st.st_size)) < 0) { perror(filename); exit(1); } if (close(fd) < 0) { perror(filename); exit(1); } if (readlen != st.st_size) { fprintf(stderr, "%s: Short read\n", filename); exit(1); } p = strrchr(argv[1], '/'); p = p ? p + 1 : argv[1]; grammar_name = strdup(p); if (!p) { perror(NULL); exit(1); } p = strchr(grammar_name, '.'); if (p) *p = '\0'; buffer[readlen] = 0; tokenise(buffer, buffer + readlen); build_type_list(); parse(); dump_elements(); out = fopen(outputname, "w"); if (!out) { perror(outputname); exit(1); } hdr = fopen(headername, "w"); if (!hdr) { perror(headername); exit(1); } render(out, hdr); if (fclose(out) < 0) { perror(outputname); exit(1); } if (fclose(hdr) < 0) { perror(headername); exit(1); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
david howellsdavid howells51897.19%250.00%
arnd bergmannarnd bergmann142.63%125.00%
colin kingcolin king10.19%125.00%
Total533100.00%4100.00%

enum compound { NOT_COMPOUND, SET, SET_OF, SEQUENCE, SEQUENCE_OF, CHOICE, ANY, TYPE_REF, TAG_OVERRIDE }; struct element { struct type *type_def; struct token *name; struct token *type; struct action *action; struct element *children; struct element *next; struct element *render_next; struct element *list_next; uint8_t n_elements;