// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2024 Google LLC
*/
#define _GNU_SOURCE
#include <assert.h>
#include <inttypes.h>
#include <stdarg.h>
#include "gendwarfksyms.h"
/* See get_union_kabi_status */
#define KABI_PREFIX "__kabi_"
#define KABI_PREFIX_LEN (sizeof(KABI_PREFIX) - 1)
#define KABI_RESERVED_PREFIX "reserved"
#define KABI_RESERVED_PREFIX_LEN (sizeof(KABI_RESERVED_PREFIX) - 1)
#define KABI_RENAMED_PREFIX "renamed"
#define KABI_RENAMED_PREFIX_LEN (sizeof(KABI_RENAMED_PREFIX) - 1)
#define KABI_IGNORED_PREFIX "ignored"
#define KABI_IGNORED_PREFIX_LEN (sizeof(KABI_IGNORED_PREFIX) - 1)
static inline bool is_kabi_prefix(const char *name)
{
return name && !strncmp(name, KABI_PREFIX, KABI_PREFIX_LEN);
}
enum kabi_status {
/* >0 to stop DIE processing */
KABI_NORMAL = 1,
KABI_RESERVED,
KABI_IGNORED,
};
static bool do_linebreak;
static int indentation_level;
/* Line breaks and indentation for pretty-printing */
static void process_linebreak(struct die *cache, int n)
{
indentation_level += n;
do_linebreak = true;
die_map_add_linebreak(cache, n);
}
#define DEFINE_GET_ATTR(attr, type) \
static bool get_##attr##_attr(Dwarf_Die *die, unsigned int id, \
type *value) \
{ \
Dwarf_Attribute da; \
return dwarf_attr(die, id, &da) && \
!dwarf_form##attr(&da, value); \
}
DEFINE_GET_ATTR(flag, bool)
DEFINE_GET_ATTR(udata, Dwarf_Word)
static bool get_ref_die_attr(Dwarf_Die *die, unsigned int id, Dwarf_Die *value)
{
Dwarf_Attribute da;
/* dwarf_formref_die returns a pointer instead of an error value. */
return dwarf_attr(die, id, &da) && dwarf_formref_die(&da, value);
}
#define DEFINE_GET_STRING_ATTR(attr) \
static const char *get_##attr##_attr(Dwarf_Die *die) \
{ \
Dwarf_Attribute da; \
if (dwarf_attr(die, DW_AT_##attr, &da)) \
return dwarf_formstring(&da); \
return NULL; \
}
DEFINE_GET_STRING_ATTR(name)
DEFINE_GET_STRING_ATTR(linkage_name)
static const char *get_symbol_name(Dwarf_Die *die)
{
const char *name;
/* rustc uses DW_AT_linkage_name for exported symbols */
name = get_linkage_name_attr(die);
if (!name)
name = get_name_attr(die);
return name;
}
static bool match_export_symbol(struct state *state, Dwarf_Die *die)
{
Dwarf_Die *source = die;
Dwarf_Die origin;
/* If the DIE has an abstract origin, use it for type information. */
if (get_ref_die_attr(die, DW_AT_abstract_origin, &origin))
source = &origin;
state->sym = symbol_get(get_symbol_name(die));
/* Look up using the origin name if there are no matches. */
if (!state->sym && source != die)
state->sym = symbol_get(get_symbol_name(source));
state->die = *source;
return !!state->sym;
}
/* DW_AT_decl_file -> struct srcfile */
static struct cache srcfile_cache;
static bool is_definition_private(Dwarf_Die *die)
{
Dwarf_Word filenum;
Dwarf_Files *files;
Dwarf_Die cudie;
const char *s;
int res;
/*
* Definitions in .c files cannot change the public ABI,
* so consider them private.
*/
if (!get_udata_attr(die, DW_AT_decl_file, &filenum))
return false;
res = cache_get(&srcfile_cache, filenum);
if (res >= 0)
return !!res