Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  kabi.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2024 Google LLC
 */


#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>

#include "gendwarfksyms.h"

#define KABI_RULE_SECTION ".discard.gendwarfksyms.kabi_rules"
#define KABI_RULE_VERSION "1"

/*
 * The rule section consists of four null-terminated strings per
 * entry:
 *
 *   1. version
 *      Entry format version. Must match KABI_RULE_VERSION.
 *
 *   2. type
 *      Type of the kABI rule. Must be one of the tags defined below.
 *
 *   3. target
 *      Rule-dependent target, typically the fully qualified name of
 *      the target DIE.
 *
 *   4. value
 *      Rule-dependent value.
 */

#define KABI_RULE_MIN_ENTRY_SIZE                                  \
 (/* version\0 */ 2 + /* type\0 */ 2 + /* target\0" */ 1 + \
  /* value\0 */ 1)
#define KABI_RULE_EMPTY_VALUE ""

/*
 * Rule: declonly
 * - For the struct/enum/union in the target field, treat it as a
 *   declaration only even if a definition is available.
 */

#define KABI_RULE_TAG_DECLONLY "declonly"

/*
 * Rule: enumerator_ignore
 * - For the enum_field in the target field, ignore the enumerator.
 */

#define KABI_RULE_TAG_ENUMERATOR_IGNORE "enumerator_ignore"

/*
 * Rule: enumerator_value
 * - For the fqn_field in the target field, set the value to the
 *   unsigned integer in the value field.
 */

#define KABI_RULE_TAG_ENUMERATOR_VALUE "enumerator_value"

/*
 * Rule: byte_size
 * - For the fqn_field in the target field, set the byte_size
 *   attribute to the value in the value field.
 */

#define KABI_RULE_TAG_BYTE_SIZE "byte_size"

/*
 * Rule: type_string
 * - For the type reference in the fqn field, use the type string
 *   in the value field.
 */

#define KABI_RULE_TAG_TYPE_STRING "type_string"

enum kabi_rule_type {
 KABI_RULE_TYPE_UNKNOWN,
 KABI_RULE_TYPE_DECLONLY,
 KABI_RULE_TYPE_ENUMERATOR_IGNORE,
 KABI_RULE_TYPE_ENUMERATOR_VALUE,
 KABI_RULE_TYPE_BYTE_SIZE,
 KABI_RULE_TYPE_TYPE_STRING,
};

#define RULE_HASH_BITS 7

struct rule {
 enum kabi_rule_type type;
 const char *target;
 const char *value;
 struct hlist_node hash;
};

/* { type, target } -> struct rule */
static HASHTABLE_DEFINE(rules, 1 << RULE_HASH_BITS);

static inline unsigned int rule_values_hash(enum kabi_rule_type type,
         const char *target)
{
 return hash_32(type) ^ hash_str(target);
}

static inline unsigned int rule_hash(const struct rule *rule)
{
 return rule_values_hash(rule->type, rule->target);
}

static inline const char *get_rule_field(const char **pos, ssize_t *left)
{
 const char *start = *pos;
 size_t len;

 if (*left <= 0)
  error("unexpected end of kABI rules");

 len = strnlen(start, *left) + 1;
 *pos += len;
 *left -= len;

 return start;
}

void kabi_read_rules(int fd)
{
 GElf_Shdr shdr_mem;
 GElf_Shdr *shdr;
 Elf_Data *rule_data = NULL;
 Elf_Scn *scn;
 Elf *elf;
 size_t shstrndx;
 const char *rule_str;
 ssize_t left;
 int i;

 const struct {
  enum kabi_rule_type type;
  const char *tag;
 } rule_types[] = {
  {
   .type = KABI_RULE_TYPE_DECLONLY,
   .tag = KABI_RULE_TAG_DECLONLY,
  },
  {
   .type = KABI_RULE_TYPE_ENUMERATOR_IGNORE,
   .tag = KABI_RULE_TAG_ENUMERATOR_IGNORE,
  },
  {
   .type = KABI_RULE_TYPE_ENUMERATOR_VALUE,
   .tag = KABI_RULE_TAG_ENUMERATOR_VALUE,
  },
  {
   .type = KABI_RULE_TYPE_BYTE_SIZE,
   .tag = KABI_RULE_TAG_BYTE_SIZE,
  },
  {
   .type = KABI_RULE_TYPE_TYPE_STRING,
   .tag = KABI_RULE_TAG_TYPE_STRING,
  },
 };

 if (!stable)
  return;

 if (elf_version(EV_CURRENT) != EV_CURRENT)
  error("elf_version failed: %s", elf_errmsg(-1));

 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
 if (!elf)
  error("elf_begin failed: %s", elf_errmsg(-1));

 if (elf_getshdrstrndx(elf, &shstrndx) < 0)
  error("elf_getshdrstrndx failed: %s", elf_errmsg(-1));

 scn = elf_nextscn(elf, NULL);

 while (scn) {
  const char *sname;

  shdr = gelf_getshdr(scn, &shdr_mem);
  if (!shdr)
   error("gelf_getshdr failed: %s", elf_errmsg(-1));

  sname = elf_strptr(elf, shstrndx, shdr->sh_name);
  if (!sname)
   error("elf_strptr failed: %s", elf_errmsg(-1));

  if (!strcmp(sname, KABI_RULE_SECTION)) {
   rule_data = elf_getdata(scn, NULL);
   if (!rule_data)
    error("elf_getdata failed: %s", elf_errmsg(-1));
   break;
  }

  scn = elf_nextscn(elf, scn);
 }

 if (!rule_data) {
  debug("kABI rules not found");
  check(elf_end(elf));
  return;
 }

 rule_str = rule_data->d_buf;
 left = shdr->sh_size;

 if (left < KABI_RULE_MIN_ENTRY_SIZE)
  error("kABI rule section too small: %zd bytes", left);

 if (rule_str[left - 1] != '\0')
  error("kABI rules are not null-terminated");

 while (left > KABI_RULE_MIN_ENTRY_SIZE) {
  enum kabi_rule_type type = KABI_RULE_TYPE_UNKNOWN;
  const char *field;
  struct rule *rule;

  /* version */
  field = get_rule_field(&rule_str, &left);

  if (strcmp(field, KABI_RULE_VERSION))
   error("unsupported kABI rule version: '%s'", field);

  /* type */
  field = get_rule_field(&rule_str, &left);

  for (i = 0; i < ARRAY_SIZE(rule_types); i++) {
   if (!strcmp(field, rule_types[i].tag)) {
    type = rule_types[i].type;
    break;
   }
  }

  if (type == KABI_RULE_TYPE_UNKNOWN)
   error("unsupported kABI rule type: '%s'", field);

  rule = xmalloc(sizeof(*rule));

  rule->type = type;
  rule->target = xstrdup(get_rule_field(&rule_str, &left));
  rule->value = xstrdup(get_rule_field(&rule_str, &left));

  hash_add(rules, &rule->hash, rule_hash(rule));

  debug("kABI rule: type: '%s', target: '%s', value: '%s'", field,
        rule->target, rule->value);
 }

 if (left > 0)
  warn("unexpected data at the end of the kABI rules section");

 check(elf_end(elf));
}

static char *get_enumerator_target(const char *fqn, const char *field)
{
 char *target = NULL;

 if (asprintf(&target, "%s %s", fqn, field) < 0)
  error("asprintf failed for '%s %s'", fqn, field);

 return target;
}

static struct rule *find_rule(enum kabi_rule_type type, const char *target)
{
 struct rule *rule;

 if (!stable)
  return NULL;
 if (!target || !*target)
  return NULL;

 hash_for_each_possible(rules, rule, hash,
          rule_values_hash(type, target)) {
  if (rule->type == type && !strcmp(target, rule->target))
   return rule;
 }

 return NULL;
}

static struct rule *find_enumerator_rule(enum kabi_rule_type type,
      const char *fqn, const char *field)
{
 struct rule *rule;
 char *target;

 if (!stable)
  return NULL;
 if (!fqn || !*fqn || !field || !*field)
  return NULL;

 target = get_enumerator_target(fqn, field);
 rule = find_rule(type, target);

 free(target);
 return rule;
}

bool kabi_is_declonly(const char *fqn)
{
 return !!find_rule(KABI_RULE_TYPE_DECLONLY, fqn);
}

static unsigned long get_ulong_value(const char *value)
{
 unsigned long result = 0;
 char *endptr = NULL;

 errno = 0;
 result = strtoul(value, &endptr, 10);

 if (errno || *endptr)
  error("invalid unsigned value '%s'", value);

 return result;
}

bool kabi_is_enumerator_ignored(const char *fqn, const char *field)
{
 return !!find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_IGNORE, fqn,
          field);
}

bool kabi_get_enumerator_value(const char *fqn, const char *field,
          unsigned long *value)
{
 struct rule *rule;

 rule = find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_VALUE, fqn,
        field);
 if (rule) {
  *value = get_ulong_value(rule->value);
  return true;
 }

 return false;
}

bool kabi_get_byte_size(const char *fqn, unsigned long *value)
{
 struct rule *rule;

 rule = find_rule(KABI_RULE_TYPE_BYTE_SIZE, fqn);
 if (rule) {
  *value = get_ulong_value(rule->value);
  return true;
 }

 return false;
}

bool kabi_get_type_string(const char *type, const char **str)
{
 struct rule *rule;

 rule = find_rule(KABI_RULE_TYPE_TYPE_STRING, type);
 if (rule) {
  *str = rule->value;
  return true;
 }

 return false;
}

void kabi_free(void)
{
 struct hlist_node *tmp;
 struct rule *rule;

 hash_for_each_safe(rules, rule, tmp, hash) {
  free((void *)rule->target);
  free((void *)rule->value);
  free(rule);
 }

 hash_init(rules);
}

Messung V0.5
C=96 H=100 G=97

¤ Dauer der Verarbeitung: 0.0 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge