Blame objects.c

Packit 400c17
/*
Packit 400c17
	Copyright(C) 2016, Red Hat, Inc., Jerome Marchand
Packit 400c17
Packit 400c17
	This program is free software: you can redistribute it and/or modify
Packit 400c17
	it under the terms of the GNU General Public License as published by
Packit 400c17
	the Free Software Foundation, either version 3 of the License, or
Packit 400c17
	(at your option) any later version.
Packit 400c17
Packit 400c17
	This program is distributed in the hope that it will be useful,
Packit 400c17
	but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 400c17
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 400c17
	GNU General Public License for more details.
Packit 400c17
Packit 400c17
	You should have received a copy of the GNU General Public License
Packit 400c17
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 400c17
*/
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Internal representation and manipulation of symbols
Packit 400c17
 */
Packit 400c17
Packit 400c17
#ifndef	_GNU_SOURCE /* We use GNU basename() that doesn't modify the arg */
Packit 400c17
#error "We need GNU version of basename()!"
Packit 400c17
#endif
Packit 400c17
Packit 400c17
#include <string.h>
Packit 400c17
#include <stdio.h>
Packit 400c17
#include <stdlib.h>
Packit 400c17
#include <stdbool.h>
Packit 400c17
#include <strings.h>
Packit 400c17
#include <limits.h>
Packit 400c17
#include <errno.h>
Packit 400c17
#include <unistd.h>
Packit 400c17
#include <getopt.h>
Packit 400c17
#include <libgen.h>
Packit 400c17
#include <sys/stat.h>
Packit 400c17
Packit 400c17
#include "objects.h"
Packit 400c17
#include "utils.h"
Packit 400c17
#include "main.h"
Packit 400c17
Packit 400c17
/* Indentation offset for c-style and tree debug outputs */
Packit 400c17
#define C_INDENT_OFFSET   8
Packit 400c17
#define DBG_INDENT_OFFSET 4
Packit 400c17
Packit 400c17
obj_list_t *obj_list_new(obj_t *obj)
Packit 400c17
{
Packit 400c17
	obj_list_t *list = safe_zmalloc(sizeof(obj_list_t));
Packit 400c17
	list->member = obj;
Packit 400c17
	list->next = NULL;
Packit 400c17
	return list;
Packit 400c17
}
Packit 400c17
Packit 400c17
static void obj_list_init(obj_list_head_t *head, obj_t *obj)
Packit 400c17
{
Packit 400c17
	obj_list_t *list = obj_list_new(obj);
Packit 400c17
	head->first = head->last = list;
Packit 400c17
}
Packit 400c17
Packit 400c17
obj_list_head_t *obj_list_head_new(obj_t *obj)
Packit 400c17
{
Packit 400c17
	obj_list_head_t *h = safe_zmalloc(sizeof(obj_list_head_t));
Packit 400c17
Packit 400c17
	obj_list_init(h, obj);
Packit 400c17
Packit 400c17
	return h;
Packit 400c17
}
Packit 400c17
Packit 400c17
static bool obj_list_empty(obj_list_head_t *head)
Packit 400c17
{
Packit 400c17
	return head->first == NULL;
Packit 400c17
}
Packit 400c17
Packit 400c17
void obj_list_add(obj_list_head_t *head, obj_t *obj)
Packit 400c17
{
Packit 400c17
	obj_list_t *list;
Packit 400c17
Packit 400c17
	if (obj_list_empty(head)) {
Packit 400c17
		obj_list_init(head, obj);
Packit 400c17
		return;
Packit 400c17
	}
Packit 400c17
	list = obj_list_new(obj);
Packit 400c17
Packit 400c17
	if (head->last->next)
Packit 400c17
		fprintf(stderr, "head->last is not the last\n");
Packit 400c17
Packit 400c17
	head->last->next = list;
Packit 400c17
	head->last = list;
Packit 400c17
}
Packit 400c17
Packit 400c17
obj_t *obj_new(obj_types type, char *name)
Packit 400c17
{
Packit 400c17
	obj_t *new = safe_zmalloc(sizeof(obj_t));
Packit 400c17
Packit 400c17
	new->type = type;
Packit 400c17
	new->name = name;
Packit 400c17
Packit 400c17
	return new;
Packit 400c17
}
Packit 400c17
Packit 400c17
static void _obj_free(obj_t *o, obj_t *skip);
Packit 400c17
Packit 400c17
static void _obj_list_free(obj_list_head_t *l, obj_t *skip)
Packit 400c17
{
Packit 400c17
	obj_list_t *list;
Packit 400c17
	obj_list_t *next;
Packit 400c17
Packit 400c17
	if (l == NULL)
Packit 400c17
		return;
Packit 400c17
Packit 400c17
	list = l->first;
Packit 400c17
	free(l);
Packit 400c17
Packit 400c17
	while (list) {
Packit 400c17
		_obj_free(list->member, skip);
Packit 400c17
		next = list->next;
Packit 400c17
		free(list);
Packit 400c17
		list = next;
Packit 400c17
	}
Packit 400c17
}
Packit 400c17
Packit 400c17
static void obj_list_free(obj_list_head_t *l)
Packit 400c17
{
Packit 400c17
	_obj_list_free(l, NULL);
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Free the tree o, but keep the subtree skip.
Packit 400c17
 */
Packit 400c17
static void _obj_free(obj_t *o, obj_t *skip)
Packit 400c17
{
Packit 400c17
	if (!o || (o == skip))
Packit 400c17
		return;
Packit 400c17
Packit 400c17
	if (o->type == __type_reffile && o->depend_rec_node) {
Packit 400c17
		list_del(o->depend_rec_node);
Packit 400c17
		o->depend_rec_node = NULL;
Packit 400c17
	}
Packit 400c17
Packit 400c17
	if (o->name)
Packit 400c17
		free(o->name);
Packit 400c17
	if (o->base_type)
Packit 400c17
		free(o->base_type);
Packit 400c17
Packit 400c17
	_obj_list_free(o->member_list, skip);
Packit 400c17
Packit 400c17
	if (o->ptr)
Packit 400c17
		_obj_free(o->ptr, skip);
Packit 400c17
Packit 400c17
	if (is_weak(o))
Packit 400c17
		free(o->link);
Packit 400c17
Packit 400c17
	free(o);
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Free the all object
Packit 400c17
 */
Packit 400c17
void obj_free(obj_t *o)
Packit 400c17
{
Packit 400c17
	_obj_free(o, NULL);
Packit 400c17
}
Packit 400c17
Packit 400c17
#define _CREATE_NEW_FUNC(type, suffix)			\
Packit 400c17
obj_t *obj_##type##_##suffix(char *name)		\
Packit 400c17
{							\
Packit 400c17
	obj_t *new = obj_new(__type_##type, name);	\
Packit 400c17
	return new;					\
Packit 400c17
}
Packit 400c17
#define CREATE_NEW_FUNC(type) _CREATE_NEW_FUNC(type, new)
Packit 400c17
#define CREATE_NEW_FUNC_NONAME(type)			\
Packit 400c17
_CREATE_NEW_FUNC(type, new_)				\
Packit 400c17
obj_t *obj_##type##_new()				\
Packit 400c17
{							\
Packit 400c17
	return obj_##type##_new_(NULL);			\
Packit 400c17
}
Packit 400c17
Packit 400c17
#define _CREATE_NEW_ADD_FUNC(type, infix)		\
Packit 400c17
obj_t *obj_##type##_##infix##_##add(char *name, obj_t *obj) \
Packit 400c17
{							\
Packit 400c17
	obj_t *new = obj_new(__type_##type, name);	\
Packit 400c17
	new->ptr = obj;					\
Packit 400c17
	return new;					\
Packit 400c17
}
Packit 400c17
#define CREATE_NEW_ADD_FUNC(type) _CREATE_NEW_ADD_FUNC(type, new)
Packit 400c17
#define CREATE_NEW_ADD_FUNC_NONAME(type)		\
Packit 400c17
_CREATE_NEW_ADD_FUNC(type, new_)			\
Packit 400c17
obj_t *obj_##type##_new_add(obj_t *obj)			\
Packit 400c17
{							\
Packit 400c17
	return obj_##type##_new__add(NULL, obj);	\
Packit 400c17
}
Packit 400c17
Packit 400c17
CREATE_NEW_FUNC(struct)
Packit 400c17
CREATE_NEW_FUNC(union)
Packit 400c17
CREATE_NEW_FUNC(enum)
Packit 400c17
CREATE_NEW_FUNC(constant)
Packit 400c17
CREATE_NEW_FUNC_NONAME(reffile)
Packit 400c17
CREATE_NEW_ADD_FUNC(func)
Packit 400c17
CREATE_NEW_ADD_FUNC(typedef)
Packit 400c17
CREATE_NEW_ADD_FUNC(var)
Packit 400c17
CREATE_NEW_ADD_FUNC(struct_member)
Packit 400c17
CREATE_NEW_ADD_FUNC_NONAME(ptr)
Packit 400c17
CREATE_NEW_ADD_FUNC_NONAME(array)
Packit 400c17
CREATE_NEW_ADD_FUNC_NONAME(qualifier)
Packit 400c17
CREATE_NEW_FUNC(assembly)
Packit 400c17
CREATE_NEW_FUNC(weak)
Packit 400c17
Packit 400c17
obj_t *obj_basetype_new(char *base_type)
Packit 400c17
{
Packit 400c17
	obj_t *new = obj_new(__type_base, NULL);
Packit 400c17
Packit 400c17
	new->base_type = base_type;
Packit 400c17
Packit 400c17
	return new;
Packit 400c17
}
Packit 400c17
Packit 400c17
const char *obj_type_name[NR_OBJ_TYPES+1] = {
Packit 400c17
	"reference file",
Packit 400c17
	"struct",
Packit 400c17
	"union",
Packit 400c17
	"enum",
Packit 400c17
	"func",
Packit 400c17
	"ptr",
Packit 400c17
	"typedef",
Packit 400c17
	"array",
Packit 400c17
	"var",
Packit 400c17
	"struct member",
Packit 400c17
	"type qualifier",
Packit 400c17
	"base",
Packit 400c17
	"constant",
Packit 400c17
	"assembly",
Packit 400c17
	"weak",
Packit 400c17
	"unknown type"
Packit 400c17
};
Packit 400c17
Packit 400c17
static const char *typetostr(obj_t *o)
Packit 400c17
{
Packit 400c17
	int t = o->type;
Packit 400c17
	if (t >= NR_OBJ_TYPES)
Packit 400c17
		t = NR_OBJ_TYPES;
Packit 400c17
	return obj_type_name[t];
Packit 400c17
}
Packit 400c17
Packit 400c17
static int c_precedence(obj_t *o)
Packit 400c17
{
Packit 400c17
	switch (o->type) {
Packit 400c17
	case __type_func:
Packit 400c17
	case __type_array:
Packit 400c17
		return 1;
Packit 400c17
	case __type_ptr:
Packit 400c17
		return 2;
Packit 400c17
	default:
Packit 400c17
		return INT_MAX;
Packit 400c17
	}
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Returns whether parentheses are needed
Packit 400c17
 *
Packit 400c17
 * Pointer have a higher precedence than function and array, so we need to put
Packit 400c17
 * parentheses around a pointer to a function of array.
Packit 400c17
 */
Packit 400c17
static bool is_paren_needed(obj_t *node)
Packit 400c17
{
Packit 400c17
	obj_t *child = node->ptr;
Packit 400c17
Packit 400c17
	while (child) {
Packit 400c17
		if (c_precedence(child) < c_precedence(node))
Packit 400c17
			return true;
Packit 400c17
Packit 400c17
		child = child->ptr;
Packit 400c17
	}
Packit 400c17
	return false;
Packit 400c17
}
Packit 400c17
Packit 400c17
static char *print_margin_offset(const char *prefix, const char *s, int depth)
Packit 400c17
{
Packit 400c17
	size_t len = snprintf(NULL, 0, "%-*s", depth * C_INDENT_OFFSET, s) + 1;
Packit 400c17
	char *ret;
Packit 400c17
Packit 400c17
	if (prefix)
Packit 400c17
		len += strlen(prefix);
Packit 400c17
Packit 400c17
	if (!len)
Packit 400c17
		return NULL;
Packit 400c17
	ret = safe_zmalloc(len);
Packit 400c17
Packit 400c17
	snprintf(ret, len, "%s%-*s",
Packit 400c17
		 prefix ? prefix : "", depth * C_INDENT_OFFSET, s);
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static char *print_margin(const char *prefix, int depth)
Packit 400c17
{
Packit 400c17
	return  print_margin_offset(prefix, "", depth);
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Return type for print_* functions
Packit 400c17
 *
Packit 400c17
 * Because C mixes prefix and postfix operator, the code generation from a node
Packit 400c17
 * may need to add code before, after or in the middle of the code generated by
Packit 400c17
 * subtrees. Thus we sometimes need two return two strings.
Packit 400c17
 *
Packit 400c17
 * Attention to the precedence and associativity sould be taken when
Packit 400c17
 * deciding where a specific string should be inserted
Packit 400c17
 */
Packit 400c17
typedef struct {
Packit 400c17
	char *prefix;
Packit 400c17
	char *postfix;
Packit 400c17
} pp_t;
Packit 400c17
Packit 400c17
static void free_pp(pp_t pp)
Packit 400c17
{
Packit 400c17
	free(pp.prefix);
Packit 400c17
	free(pp.postfix);
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t _print_tree(obj_t *o, int depth, bool newline, const char *prefix);
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Add prefix p at the begining of string s (reallocated)
Packit 400c17
 *
Packit 400c17
 * space: add a space between p and s
Packit 400c17
 * freep: free the string p
Packit 400c17
 */
Packit 400c17
static char *_prefix_str(char **s, char *p, bool space, bool freep)
Packit 400c17
{
Packit 400c17
	size_t lenp = strlen(p), lens = 0, newlen;
Packit 400c17
Packit 400c17
	if (*s)
Packit 400c17
		lens = strlen(*s);
Packit 400c17
	newlen = lens + lenp + 1;
Packit 400c17
Packit 400c17
	if (space)
Packit 400c17
		newlen++;
Packit 400c17
Packit 400c17
	*s = safe_realloc(*s, newlen);
Packit 400c17
Packit 400c17
	if (lens)
Packit 400c17
		memmove(space ? *s+lenp+1 : *s+lenp, *s, lens + 1);
Packit 400c17
	else
Packit 400c17
		(*s)[lenp] = '\0';
Packit 400c17
	memcpy(*s, p, lenp);
Packit 400c17
	if (space)
Packit 400c17
		(*s)[lenp] = ' ';
Packit 400c17
Packit 400c17
	if (freep)
Packit 400c17
		free(p);
Packit 400c17
Packit 400c17
	return *s;
Packit 400c17
}
Packit 400c17
Packit 400c17
static char *prefix_str(char **s, char *p)
Packit 400c17
{
Packit 400c17
	if (!p)
Packit 400c17
		return *s;
Packit 400c17
	return _prefix_str(s, p, false, false);
Packit 400c17
}
Packit 400c17
Packit 400c17
static char *prefix_str_free(char **s, char *p)
Packit 400c17
{
Packit 400c17
	if (!p)
Packit 400c17
		return *s;
Packit 400c17
	return _prefix_str(s, p, false, true);
Packit 400c17
}
Packit 400c17
Packit 400c17
static char *prefix_str_space(char **s, char *p)
Packit 400c17
{
Packit 400c17
	if (!p)
Packit 400c17
		return *s;
Packit 400c17
	return _prefix_str(s, p, true, false);
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Add suffix p at the end of string s (realocated)
Packit 400c17
 *
Packit 400c17
 * space: add a space between p and s
Packit 400c17
 * freep: free the string p
Packit 400c17
 */
Packit 400c17
static char *_postfix_str(char **s, char *p, bool space, bool freep)
Packit 400c17
{
Packit 400c17
	int lenp = strlen(p), lens = 0, newlen;
Packit 400c17
	if (*s)
Packit 400c17
		lens = strlen(*s);
Packit 400c17
	newlen = lens + lenp + 1;
Packit 400c17
Packit 400c17
	if (space)
Packit 400c17
		newlen++;
Packit 400c17
Packit 400c17
	*s = safe_realloc(*s, newlen);
Packit 400c17
Packit 400c17
	if (lens == 0)
Packit 400c17
		(*s)[0] = '\0';
Packit 400c17
	if (space)
Packit 400c17
		strcat(*s, " ");
Packit 400c17
	strcat(*s, p);
Packit 400c17
Packit 400c17
	if (freep)
Packit 400c17
		free(p);
Packit 400c17
Packit 400c17
	return *s;
Packit 400c17
}
Packit 400c17
Packit 400c17
static char *postfix_str(char **s, char *p)
Packit 400c17
{
Packit 400c17
	if (!p)
Packit 400c17
		return *s;
Packit 400c17
	return _postfix_str(s, p, false, false);
Packit 400c17
}
Packit 400c17
Packit 400c17
static char *postfix_str_free(char **s, char *p)
Packit 400c17
{
Packit 400c17
	if (!p)
Packit 400c17
		return *s;
Packit 400c17
	return _postfix_str(s, p, false, true);
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_base(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret = {NULL, NULL};
Packit 400c17
Packit 400c17
	safe_asprintf(&ret.prefix, "%s ", o->base_type);
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_constant(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret = {NULL, NULL};
Packit 400c17
Packit 400c17
	safe_asprintf(&ret.prefix, "%s = %li", o->name, (long)o->constant);
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_reffile(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret = {NULL, NULL};
Packit 400c17
	char *s = filenametotype(o->base_type);
Packit 400c17
Packit 400c17
	s = safe_realloc(s, strlen(s) + 2);
Packit 400c17
	strcat(s, " ");
Packit 400c17
	ret.prefix = s;
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
/* Print a struct, enum or an union */
Packit 400c17
static pp_t print_structlike(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret = {NULL, NULL}, tmp;
Packit 400c17
	obj_list_t *list = NULL;
Packit 400c17
	char *s, *margin;
Packit 400c17
Packit 400c17
	if (o->name)
Packit 400c17
		safe_asprintf(&s, "%s %s {\n", typetostr(o), o->name);
Packit 400c17
	else
Packit 400c17
		safe_asprintf(&s, "%s {\n", typetostr(o));
Packit 400c17
Packit 400c17
	if (o->member_list)
Packit 400c17
		list = o->member_list->first;
Packit 400c17
	while (list) {
Packit 400c17
		tmp = _print_tree(list->member, depth+1, true, prefix);
Packit 400c17
		postfix_str_free(&s, tmp.prefix);
Packit 400c17
		postfix_str_free(&s, tmp.postfix);
Packit 400c17
		postfix_str(&s, o->type == __type_enum ? ",\n" : ";\n");
Packit 400c17
		list = list->next;
Packit 400c17
	}
Packit 400c17
Packit 400c17
	margin = print_margin(prefix, depth);
Packit 400c17
	postfix_str_free(&s, margin);
Packit 400c17
	postfix_str(&s, "}");
Packit 400c17
Packit 400c17
	ret.prefix = s;
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_func(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret = {NULL, NULL}, return_type;
Packit 400c17
	obj_list_t *list = NULL;
Packit 400c17
	obj_t *next = o->ptr;
Packit 400c17
	char *s, *name, *margin;
Packit 400c17
Packit 400c17
	return_type = _print_tree(next, depth, false, prefix);
Packit 400c17
	ret.prefix = return_type.prefix;
Packit 400c17
Packit 400c17
	if (o->name)
Packit 400c17
		name = o->name;
Packit 400c17
	else
Packit 400c17
		name = "";
Packit 400c17
Packit 400c17
	safe_asprintf(&s, "%s(\n", name);
Packit 400c17
Packit 400c17
	if (o->member_list)
Packit 400c17
		list = o->member_list->first;
Packit 400c17
	while (list) {
Packit 400c17
		pp_t arg = _print_tree(list->member, depth+1, true, prefix);
Packit 400c17
		postfix_str_free(&s, arg.prefix);
Packit 400c17
		postfix_str_free(&s, arg.postfix);
Packit 400c17
		list = list->next;
Packit 400c17
		postfix_str(&s, list ? ",\n" : "\n");
Packit 400c17
	}
Packit 400c17
Packit 400c17
	margin = print_margin(prefix, depth);
Packit 400c17
	postfix_str_free(&s, margin);
Packit 400c17
	postfix_str(&s, ")");
Packit 400c17
Packit 400c17
	ret.postfix = s;
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_array(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret;
Packit 400c17
	char *s;
Packit 400c17
	obj_t *next = o->ptr;
Packit 400c17
Packit 400c17
	ret = _print_tree(next, depth, false, prefix);
Packit 400c17
Packit 400c17
	safe_asprintf(&s, "[%lu]", o->constant);
Packit 400c17
	prefix_str_free(&ret.postfix, s);
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_ptr(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret;
Packit 400c17
	bool need_paren = is_paren_needed(o);
Packit 400c17
	obj_t *next = o->ptr;
Packit 400c17
Packit 400c17
	ret = _print_tree(next, depth, false, prefix);
Packit 400c17
	if (need_paren) {
Packit 400c17
		postfix_str(&ret.prefix, "(*");
Packit 400c17
		prefix_str(&ret.postfix, ")");
Packit 400c17
	} else
Packit 400c17
		postfix_str(&ret.prefix, "*");
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
/* Print a var or a struct_member */
Packit 400c17
static pp_t print_varlike(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret;
Packit 400c17
	char *s = NULL;
Packit 400c17
Packit 400c17
	if (is_bitfield(o))
Packit 400c17
		safe_asprintf(&s, "%s:%i",
Packit 400c17
			      o->name, o->last_bit - o->first_bit + 1);
Packit 400c17
	else
Packit 400c17
		s = o->name;
Packit 400c17
Packit 400c17
	ret = _print_tree(o->ptr, depth, false, prefix);
Packit 400c17
Packit 400c17
	if (s)
Packit 400c17
		postfix_str(&ret.prefix, s);
Packit 400c17
Packit 400c17
	if (is_bitfield(o))
Packit 400c17
		free(s);
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_typedef(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret;
Packit 400c17
Packit 400c17
	ret = _print_tree(o->ptr, depth, false, prefix);
Packit 400c17
Packit 400c17
	prefix_str(&ret.prefix, "typedef ");
Packit 400c17
	postfix_str(&ret.prefix, o->name);
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_qualifier(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret;
Packit 400c17
Packit 400c17
	ret = _print_tree(o->ptr, depth, false, prefix);
Packit 400c17
	prefix_str_space(&ret.prefix, o->base_type);
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_assembly(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret = {NULL, NULL};
Packit 400c17
Packit 400c17
	prefix_str(&ret.prefix, "assembly ");
Packit 400c17
	postfix_str(&ret.prefix, o->name);
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static pp_t print_weak(obj_t *o, int depth, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret = {NULL, NULL};
Packit 400c17
Packit 400c17
	prefix_str(&ret.prefix, "weak ");
Packit 400c17
	postfix_str(&ret.prefix, o->name);
Packit 400c17
	postfix_str(&ret.prefix, " -> ");
Packit 400c17
	postfix_str(&ret.prefix, o->link);
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
#define BASIC_CASE(type)				\
Packit 400c17
	case __type_##type:				\
Packit 400c17
		ret = print_##type(o, depth, prefix);	\
Packit 400c17
		break;
Packit 400c17
Packit 400c17
struct dopt display_options;
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Display an object in a c-like format
Packit 400c17
 *
Packit 400c17
 * o:	    object to be displayed
Packit 400c17
 * depth:   current indentation depth
Packit 400c17
 * newline: is this the begining of a new line?
Packit 400c17
 * prefix:  prefix to be printed at the begining of each line
Packit 400c17
 */
Packit 400c17
static pp_t _print_tree(obj_t *o, int depth, bool newline, const char *prefix)
Packit 400c17
{
Packit 400c17
	pp_t ret = {NULL, NULL};
Packit 400c17
	char *margin;
Packit 400c17
Packit 400c17
	/* silence coverity on write-only variable */
Packit 400c17
	(void)ret;
Packit 400c17
Packit 400c17
	if (!o)
Packit 400c17
		fail("NULL pointer in _print_tree\n");
Packit 400c17
	debug("_print_tree(): %s\n", typetostr(o));
Packit 400c17
Packit 400c17
	switch (o->type) {
Packit 400c17
	BASIC_CASE(reffile);
Packit 400c17
	BASIC_CASE(constant);
Packit 400c17
	BASIC_CASE(base);
Packit 400c17
	BASIC_CASE(typedef);
Packit 400c17
	BASIC_CASE(qualifier);
Packit 400c17
	BASIC_CASE(func);
Packit 400c17
	BASIC_CASE(array);
Packit 400c17
	BASIC_CASE(ptr);
Packit 400c17
	BASIC_CASE(assembly);
Packit 400c17
	BASIC_CASE(weak);
Packit 400c17
	case __type_var:
Packit 400c17
	case __type_struct_member:
Packit 400c17
		ret = print_varlike(o, depth, prefix);
Packit 400c17
		break;
Packit 400c17
	case __type_struct:
Packit 400c17
	case __type_union:
Packit 400c17
	case __type_enum:
Packit 400c17
		ret = print_structlike(o, depth, prefix);
Packit 400c17
		break;
Packit 400c17
	default:
Packit 400c17
		fail("WIP: doesn't handle %s\n", typetostr(o));
Packit 400c17
	}
Packit 400c17
Packit 400c17
	if (!newline)
Packit 400c17
		return ret;
Packit 400c17
Packit 400c17
	if (o->type == __type_struct_member && !display_options.no_offset) {
Packit 400c17
		char *offstr;
Packit 400c17
		if (is_bitfield(o))
Packit 400c17
			safe_asprintf(&offstr, "0x%lx:%2i-%-2i ",
Packit 400c17
				      o->offset, o->first_bit, o->last_bit);
Packit 400c17
		else
Packit 400c17
			safe_asprintf(&offstr, "0x%lx ", o->offset);
Packit 400c17
		margin = print_margin_offset(prefix, offstr, depth);
Packit 400c17
		free(offstr);
Packit 400c17
	} else
Packit 400c17
		margin = print_margin(prefix, depth);
Packit 400c17
Packit 400c17
	prefix_str_free(&ret.prefix, margin);
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
void obj_print_tree__prefix(obj_t *root, const char *prefix, FILE *stream)
Packit 400c17
{
Packit 400c17
	pp_t s = _print_tree(root, 0, true, prefix);
Packit 400c17
Packit 400c17
	fprintf(stream, "%s%s;\n",
Packit 400c17
	       s.prefix ? s.prefix : "",
Packit 400c17
	       s.postfix ? s.postfix : "");
Packit 400c17
	free_pp(s);
Packit 400c17
}
Packit 400c17
Packit 400c17
void obj_print_tree(obj_t *root)
Packit 400c17
{
Packit 400c17
	obj_print_tree__prefix(root, NULL, stdout);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void fill_parent_rec(obj_t *o, obj_t *parent)
Packit 400c17
{
Packit 400c17
	obj_list_t *list = NULL;
Packit 400c17
Packit 400c17
	o->parent = parent;
Packit 400c17
Packit 400c17
	if (o->member_list)
Packit 400c17
		list = o->member_list->first;
Packit 400c17
Packit 400c17
	while (list) {
Packit 400c17
		fill_parent_rec(list->member, o);
Packit 400c17
		list = list->next;
Packit 400c17
	}
Packit 400c17
Packit 400c17
	if (o->ptr)
Packit 400c17
		fill_parent_rec(o->ptr, o);
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Walk the tree and fill all the parents field
Packit 400c17
 */
Packit 400c17
void obj_fill_parent(obj_t *root)
Packit 400c17
{
Packit 400c17
	fill_parent_rec(root, NULL);
Packit 400c17
}
Packit 400c17
Packit 400c17
static int walk_list(obj_list_t *list, cb_t cb_pre, cb_t cb_in, cb_t cb_post,
Packit 400c17
			void *args, bool ptr_first)
Packit 400c17
{
Packit 400c17
	int ret = CB_CONT;
Packit 400c17
Packit 400c17
	while (list) {
Packit 400c17
		ret = obj_walk_tree3(list->member, cb_pre, cb_in, cb_post,
Packit 400c17
				 args, ptr_first);
Packit 400c17
		if (ret == CB_FAIL)
Packit 400c17
			return ret;
Packit 400c17
		else
Packit 400c17
			ret = CB_CONT;
Packit 400c17
		list = list->next;
Packit 400c17
	}
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
static int walk_ptr(obj_t *o, cb_t cb_pre, cb_t cb_in, cb_t cb_post,
Packit 400c17
			void *args, bool ptr_first)
Packit 400c17
{
Packit 400c17
	int ret = CB_CONT;
Packit 400c17
Packit 400c17
	if (o->ptr) {
Packit 400c17
		ret = obj_walk_tree3(o->ptr, cb_pre, cb_in, cb_post,
Packit 400c17
				 args, ptr_first);
Packit 400c17
		if (ret == CB_FAIL)
Packit 400c17
			return ret;
Packit 400c17
		else
Packit 400c17
			ret = CB_CONT;
Packit 400c17
	}
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Tree walk with prefix, infix and postfix callbacks
Packit 400c17
 *
Packit 400c17
 * o:	      walked tree
Packit 400c17
 * cb_pre:    callback function called before walking the subtrees
Packit 400c17
 * cb_in:     callback function called between walking the subtrees
Packit 400c17
 * cp_post:   callback function called between walking the subtrees
Packit 400c17
 * args:      argument passed to the callbacks
Packit 400c17
 * ptr_first: whether we walk member_list of ptr first
Packit 400c17
 */
Packit 400c17
int obj_walk_tree3(obj_t *o, cb_t cb_pre, cb_t cb_in, cb_t cb_post,
Packit 400c17
			void *args, bool ptr_first)
Packit 400c17
{
Packit 400c17
	obj_list_t *list = NULL;
Packit 400c17
	int ret = CB_CONT;
Packit 400c17
Packit 400c17
	if (cb_pre) {
Packit 400c17
		ret = cb_pre(o, args);
Packit 400c17
		if (ret)
Packit 400c17
			return ret;
Packit 400c17
	}
Packit 400c17
Packit 400c17
	if (o->member_list)
Packit 400c17
		list = o->member_list->first;
Packit 400c17
Packit 400c17
Packit 400c17
	if (ptr_first)
Packit 400c17
		ret = walk_ptr(o, cb_pre, cb_in, cb_post, args, ptr_first);
Packit 400c17
	else
Packit 400c17
		ret = walk_list(list, cb_pre, cb_in, cb_post, args, ptr_first);
Packit 400c17
	if (ret == CB_FAIL)
Packit 400c17
		return ret;
Packit 400c17
Packit 400c17
	if (cb_in) {
Packit 400c17
		ret = cb_in(o, args);
Packit 400c17
		if (ret)
Packit 400c17
			return ret;
Packit 400c17
	}
Packit 400c17
Packit 400c17
	if (ptr_first)
Packit 400c17
		ret = walk_list(list, cb_pre, cb_in, cb_post, args, ptr_first);
Packit 400c17
	else
Packit 400c17
		ret = walk_ptr(o, cb_pre, cb_in, cb_post, args, ptr_first);
Packit 400c17
	if (ret == CB_FAIL)
Packit 400c17
		return ret;
Packit 400c17
Packit 400c17
	if (cb_post) {
Packit 400c17
		ret = cb_post(o, args);
Packit 400c17
		if (ret)
Packit 400c17
			return ret;
Packit 400c17
	}
Packit 400c17
Packit 400c17
	return ret;
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Simple tree walk with a prefix callback
Packit 400c17
 *
Packit 400c17
 * It walks the member_list subtree first.
Packit 400c17
 */
Packit 400c17
int obj_walk_tree(obj_t *root, cb_t cb, void *args)
Packit 400c17
{
Packit 400c17
	return obj_walk_tree3(root, cb, NULL, NULL, args, false);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void _show_node(FILE *f, obj_t *o, int margin)
Packit 400c17
{
Packit 400c17
	if (o)
Packit 400c17
		fprintf(f,
Packit 400c17
			"\%*s<%s, \"%s\", \"%s\", %p, %p, %p, %lu, %i, %i>\n",
Packit 400c17
			margin, "", typetostr(o), o->name, o->base_type,
Packit 400c17
			o, o->parent, o->ptr,
Packit 400c17
			o->offset, o->first_bit, o->last_bit);
Packit 400c17
	else
Packit 400c17
		fprintf(f, "\%*s<(nil)>\n", margin, "");
Packit 400c17
}
Packit 400c17
Packit 400c17
static void show_node(obj_t *o, int margin)
Packit 400c17
{
Packit 400c17
	_show_node(stdout, o, margin);
Packit 400c17
}
Packit 400c17
Packit 400c17
static int debug_node(obj_t *node, void *args)
Packit 400c17
{
Packit 400c17
	int *depth = (int *) args;
Packit 400c17
Packit 400c17
	show_node(node, *depth * DBG_INDENT_OFFSET);
Packit 400c17
	(*depth)++;
Packit 400c17
Packit 400c17
	return CB_CONT;
Packit 400c17
}
Packit 400c17
Packit 400c17
static int dec_depth(obj_t *node, void *args)
Packit 400c17
{
Packit 400c17
	int *depth = (int *) args;
Packit 400c17
Packit 400c17
	(*depth)--;
Packit 400c17
Packit 400c17
	return CB_CONT;
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Print a raw representation of the internal object tree
Packit 400c17
 */
Packit 400c17
int obj_debug_tree(obj_t *root)
Packit 400c17
{
Packit 400c17
	int depth = 0;
Packit 400c17
Packit 400c17
	return obj_walk_tree3(root, debug_node, NULL, dec_depth, &depth, false);
Packit 400c17
}
Packit 400c17
Packit 400c17
/*
Packit 400c17
 * Hide some RH_KABI magic
Packit 400c17
 *
Packit 400c17
 * WARNING: this code is ugly and full of add-hoc hacks, but I'm
Packit 400c17
 * afraid it can't be fixed. It has to follow the internals of
Packit 400c17
 * RH_KABI_* macros. Also, it may have to change if RH_KABI_*
Packit 400c17
 * functions change in the future.
Packit 400c17
 *
Packit 400c17
 * RH_KABI_REPLACE the old field by a complex construction of union
Packit 400c17
 * and struct used to check that the new field didn't change the
Packit 400c17
 * alignement. It is of the form:
Packit 400c17
 * union {
Packit 400c17
 *	_new;
Packit 400c17
 *	struct {
Packit 400c17
 *		_orig;
Packit 400c17
 *	} __UNIQUE_ID_rh_kabi_hideXX
Packit 400c17
 *	union {};
Packit 400c17
 * }
Packit 400c17
 *
Packit 400c17
 * RH_KABI_USE2(_P) replace a single field by two field that fits in
Packit 400c17
 * the same space. It puts the two new field into an unnamed
Packit 400c17
 * struct. We don't hide that as we have no way to know if that struct
Packit 400c17
 * is an artifact from RH_KABI_USE2 or was added deliberately.
Packit 400c17
 *
Packit 400c17
 * RH_KABI_DEPRECATE(_FN) prefix the field name with
Packit 400c17
 * rh_reserved_. This is not the most specific string. It currently
Packit 400c17
 * appears in a few places that deprecates the field by hand, in which
Packit 400c17
 * it's OK to hide it too, but for some reason in
Packit 400c17
 * block_device_operations the reserved fields are of the form "void
Packit 400c17
 * *rh_reserved_ptrsX" instead of the usual "unsigned long
Packit 400c17
 * rh_reservedX". Treat this case as an exception.
Packit 400c17
 *
Packit 400c17
 * Most RH_KABI_* functions, don't add any recognizable code so we
Packit 400c17
 * can't hide them here.
Packit 400c17
 */
Packit 400c17
static int hide_kabi_cb(obj_t *o, void *args)
Packit 400c17
{
Packit 400c17
	obj_t *kabi_struct, *new, *old, *parent = o->parent, *keeper;
Packit 400c17
	obj_list_head_t *lh;
Packit 400c17
	obj_list_t *l;
Packit 400c17
	bool show_new_field = (bool) args;
Packit 400c17
Packit 400c17
	if (o->name) {
Packit 400c17
		if (!strncmp(o->name, RH_KABI_HIDE, RH_KABI_HIDE_LEN))
Packit 400c17
			fail("Missed a kabi unique ID\n");
Packit 400c17
Packit 400c17
		/* Hide RH_KABI_DEPRECATE* */
Packit 400c17
		if (!strncmp(o->name, "rh_reserved_", 12) &&
Packit 400c17
		    strncmp(o->name, "rh_reserved_ptrs", 16)) {
Packit 400c17
			char *tmp = strdup(o->name+12);
Packit 400c17
			free(o->name);
Packit 400c17
			o->name = tmp;
Packit 400c17
		}
Packit 400c17
	}
Packit 400c17
Packit 400c17
	/* Hide RH_KABI_REPLACE */
Packit 400c17
	if ((o->type != __type_union) || o->name ||
Packit 400c17
	    !(lh = o->member_list) || obj_list_empty(lh) ||
Packit 400c17
	    !(l = lh->first) || !(new = l->member) ||
Packit 400c17
	    !(l = l->next) || !(kabi_struct = l->member) ||
Packit 400c17
	    (kabi_struct->type != __type_var) ||
Packit 400c17
	    !kabi_struct->name ||
Packit 400c17
	    strncmp(kabi_struct->name, RH_KABI_HIDE, RH_KABI_HIDE_LEN))
Packit 400c17
		return CB_CONT;
Packit 400c17
Packit 400c17
	if (!kabi_struct->ptr || kabi_struct->ptr->type != __type_struct ||
Packit 400c17
	    !(lh = kabi_struct->ptr->member_list) || obj_list_empty(lh) ||
Packit 400c17
	    !(l = lh->first) || !(old = l->member))
Packit 400c17
		fail("Unexpeted rh_kabi_hide struct format\n");
Packit 400c17
Packit 400c17
	/*
Packit 400c17
	 * It is a rh_kabi_hide union
Packit 400c17
	 * old is the first member of kabi_struct
Packit 400c17
	 *
Packit 400c17
	 * Need to replace that:
Packit 400c17
	 * <struct member, "(null)", "(null)", 0x1ea9840 16 0 0> (parent)
Packit 400c17
	 *    <union, "(null)", "(null)", (nil) 0 0 0>		 (o)
Packit 400c17
	 *       <var, "new_field", "(null)", 0x1ea9540 0 0 0>	 (new)
Packit 400c17
	 *          <base, "(null)", "int", (nil) 0 0 0>
Packit 400c17
	 *       <var, "__UNIQUE_ID_rh_kabi_hide55", "(null)", 0x1ea9700 0 0 0>
Packit 400c17
	 *          <struct, "(null)", "(null)", (nil) 0 0 0>
Packit 400c17
	 *             <struct member, "old_field", "(null)", 0x1ea9640 0 0 0>
Packit 400c17
	 *                <base, "(null)", "int", (nil) 0 0 0>		^(old)
Packit 400c17
	 *       <var, "(null)", "(null)", 0x1ea97a0 0 0 0>
Packit 400c17
	 *          <union, "(null)", "(null)", (nil) 0 0 0>
Packit 400c17
	 *
Packit 400c17
	 * by that:
Packit 400c17
	 * <struct member, "new_field", "(null)", 0x1ea9540 16 0 0>
Packit 400c17
	 *    <base, "(null)", "int", (nil) 0 0 0>
Packit 400c17
	 *
Packit 400c17
	 * or that:
Packit 400c17
	 * <struct member, "old_field", "(null)", 0x1ea9640 0 0 0>
Packit 400c17
	 *    <base, "(null)", "int", (nil) 0 0 0>
Packit 400c17
	 *
Packit 400c17
	 * Parent is always an unary node, struct_member or var
Packit 400c17
	 */
Packit 400c17
Packit 400c17
	if (!parent ||
Packit 400c17
	    !((parent->type == __type_var) ||
Packit 400c17
	    (parent->type == __type_struct_member)) ||
Packit 400c17
	    (parent->ptr != o) || parent->name) {
Packit 400c17
		_show_node(stderr, parent, 0);
Packit 400c17
		fail("Unexpected parent\n");
Packit 400c17
	}
Packit 400c17
	if (new->type != __type_var) {
Packit 400c17
		_show_node(stderr, new, 0);
Packit 400c17
		fail("Unexpected new field\n");
Packit 400c17
	}
Packit 400c17
	if (old->type != __type_struct_member) {
Packit 400c17
		_show_node(stderr, old, 0);
Packit 400c17
		fail("Unexpected old field\n");
Packit 400c17
	}
Packit 400c17
Packit 400c17
	keeper = show_new_field ? new : old;
Packit 400c17
Packit 400c17
	parent->name = keeper->name;
Packit 400c17
	parent->ptr = keeper->ptr;
Packit 400c17
	parent->ptr->parent = parent;
Packit 400c17
	_obj_free(o, keeper);
Packit 400c17
	free(keeper);
Packit 400c17
Packit 400c17
	return CB_SKIP;
Packit 400c17
}
Packit 400c17
Packit 400c17
int obj_hide_kabi(obj_t *root, bool show_new_field)
Packit 400c17
{
Packit 400c17
	return obj_walk_tree(root, hide_kabi_cb, (void *)show_new_field);
Packit 400c17
}
Packit 400c17
Packit 400c17
static bool obj_is_declaration(obj_t *obj)
Packit 400c17
{
Packit 400c17
	size_t len;
Packit 400c17
Packit 400c17
	if (obj->base_type == NULL)
Packit 400c17
		return false;
Packit 400c17
Packit 400c17
	len = strlen(DECLARATION_PATH);
Packit 400c17
	return strncmp(obj->base_type, DECLARATION_PATH, len) == 0;
Packit 400c17
}
Packit 400c17
Packit 400c17
static bool obj_is_kabi_hide(obj_t *obj)
Packit 400c17
{
Packit 400c17
	if (obj->name == NULL)
Packit 400c17
		return false;
Packit 400c17
Packit 400c17
	return strncmp(obj->name, RH_KABI_HIDE, RH_KABI_HIDE_LEN) == 0;
Packit 400c17
}
Packit 400c17
Packit 400c17
static bool obj_eq(obj_t *o1, obj_t *o2)
Packit 400c17
{
Packit 400c17
	/* borrow parts from cmp_nodes */
Packit 400c17
	if ((o1->type != o2->type) ||
Packit 400c17
	    !safe_streq(o1->name, o2->name) ||
Packit 400c17
	    ((o1->ptr == NULL) != (o2->ptr == NULL)) ||
Packit 400c17
	    (has_constant(o1) && (o1->constant != o2->constant)) ||
Packit 400c17
	    (has_index(o1) && (o1->index != o2->index)) ||
Packit 400c17
	    (is_bitfield(o1) != is_bitfield(o2)) ||
Packit 400c17
	    (o1->alignment != o2->alignment))
Packit 400c17
		return false;
Packit 400c17
Packit 400c17
	/* just compare bitfields */
Packit 400c17
	if (is_bitfield(o1) &&
Packit 400c17
	    ((o1->last_bit !=  o2->last_bit) ||
Packit 400c17
	     (o1->first_bit != o2->first_bit)))
Packit 400c17
		return false;
Packit 400c17
Packit 400c17
	if ((o1->member_list == NULL) !=
Packit 400c17
	    (o2->member_list == NULL))
Packit 400c17
		return false;
Packit 400c17
Packit 400c17
	if (!safe_streq(o1->base_type, o2->base_type))
Packit 400c17
		return false;
Packit 400c17
Packit 400c17
	return true;
Packit 400c17
}
Packit 400c17
Packit 400c17
static obj_t *obj_copy(obj_t *o1)
Packit 400c17
{
Packit 400c17
	obj_t *o;
Packit 400c17
Packit 400c17
	o = safe_zmalloc(sizeof(*o));
Packit 400c17
	*o = *o1;
Packit 400c17
Packit 400c17
	o->type = o1->type;
Packit 400c17
	o->name = safe_strdup_or_null(o1->name);
Packit 400c17
	o->base_type = safe_strdup_or_null(o1->base_type);
Packit 400c17
Packit 400c17
	o->ptr = NULL;
Packit 400c17
	o->member_list = NULL;
Packit 400c17
Packit 400c17
	if (o1->type == __type_reffile && o1->depend_rec_node)
Packit 400c17
		o->depend_rec_node = list_node_add(o1->depend_rec_node, o);
Packit 400c17
Packit 400c17
	return o;
Packit 400c17
}
Packit 400c17
Packit 400c17
obj_t *obj_merge(obj_t *o1, obj_t *o2, bool merge_decl);
Packit 400c17
Packit 400c17
static obj_list_head_t *obj_members_merge(obj_list_head_t *list1,
Packit 400c17
		obj_list_head_t *list2, bool merge_decl)
Packit 400c17
{
Packit 400c17
	obj_list_head_t *res = NULL;
Packit 400c17
	obj_list_t *l1;
Packit 400c17
	obj_list_t *l2;
Packit 400c17
	obj_t *o;
Packit 400c17
Packit 400c17
	if (list1 == NULL || list2 == NULL)
Packit 400c17
		return NULL;
Packit 400c17
Packit 400c17
	l1 = list1->first;
Packit 400c17
	l2 = list2->first;
Packit 400c17
Packit 400c17
	while (l1 && l2) {
Packit 400c17
		o = obj_merge(l1->member, l2->member, merge_decl);
Packit 400c17
		if (o == NULL)
Packit 400c17
			goto cleanup;
Packit 400c17
Packit 400c17
		if (res == NULL)
Packit 400c17
			res = obj_list_head_new(o);
Packit 400c17
		else
Packit 400c17
			obj_list_add(res, o);
Packit 400c17
Packit 400c17
		l1 = l1->next;
Packit 400c17
		l2 = l2->next;
Packit 400c17
	};
Packit 400c17
Packit 400c17
	if (l1 || l2)
Packit 400c17
		goto cleanup;
Packit 400c17
Packit 400c17
	return res;
Packit 400c17
Packit 400c17
cleanup:
Packit 400c17
	obj_list_free(res);
Packit 400c17
	return NULL;
Packit 400c17
}
Packit 400c17
Packit 400c17
obj_t *obj_merge(obj_t *o1, obj_t *o2, bool merge_decl)
Packit 400c17
{
Packit 400c17
	obj_t *merged_ptr;
Packit 400c17
	obj_list_head_t *merged_members;
Packit 400c17
	obj_t *res = NULL;
Packit 400c17
Packit 400c17
	if (o1 == NULL || o2 == NULL)
Packit 400c17
		return NULL;
Packit 400c17
Packit 400c17
	/*
Packit 400c17
	 * We can merge the two lines if:
Packit 400c17
	 *  - they are the same, or
Packit 400c17
	 *  - they are both RH_KABI_HIDE, or
Packit 400c17
	 *  - at least one of them is a declaration
Packit 400c17
	 */
Packit 400c17
	if ((!obj_eq(o1, o2)) &&
Packit 400c17
	    (!obj_is_kabi_hide(o1) || !obj_is_kabi_hide(o2)) &&
Packit 400c17
	    !(obj_is_declaration(o1) && merge_decl) &&
Packit 400c17
	    !(obj_is_declaration(o2) && merge_decl))
Packit 400c17
		goto no_merge;
Packit 400c17
Packit 400c17
	merged_ptr = obj_merge(o1->ptr, o2->ptr, merge_decl);
Packit 400c17
	if (o1->ptr && !merged_ptr)
Packit 400c17
		goto no_merge_ptr;
Packit 400c17
Packit 400c17
	merged_members = obj_members_merge(o1->member_list,
Packit 400c17
					   o2->member_list,
Packit 400c17
					   merge_decl);
Packit 400c17
	if (o1->member_list && !merged_members)
Packit 400c17
		goto no_merge_members;
Packit 400c17
Packit 400c17
	if (obj_is_declaration(o1))
Packit 400c17
		res = obj_copy(o2);
Packit 400c17
	else
Packit 400c17
		res = obj_copy(o1);
Packit 400c17
Packit 400c17
	res->ptr = merged_ptr;
Packit 400c17
Packit 400c17
	if (merged_members != NULL)
Packit 400c17
		merged_members->object = res;
Packit 400c17
	res->member_list = merged_members;
Packit 400c17
Packit 400c17
	return res;
Packit 400c17
Packit 400c17
no_merge_members:
Packit 400c17
	obj_list_free(merged_members);
Packit 400c17
no_merge_ptr:
Packit 400c17
	obj_free(merged_ptr);
Packit 400c17
no_merge:
Packit 400c17
	return NULL;
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_reffile(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "@\"%s\"\n", o->base_type);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void _dump_members(obj_t *o, FILE *f, void (*dumper)(obj_t *, FILE *))
Packit 400c17
{
Packit 400c17
	obj_list_head_t *l = o->member_list;
Packit 400c17
	obj_list_t *list;
Packit 400c17
Packit 400c17
	if (l == NULL)
Packit 400c17
		return;
Packit 400c17
Packit 400c17
	list = l->first;
Packit 400c17
Packit 400c17
	while (list) {
Packit 400c17
		dumper(list->member, f);
Packit 400c17
		list = list->next;
Packit 400c17
	}
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_arg(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "%s ", o->name);
Packit 400c17
	obj_dump(o->ptr, f);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_members(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	_dump_members(o, f, obj_dump);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_args(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	_dump_members(o, f, dump_arg);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_struct(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "struct %s {\n", o->name);
Packit 400c17
	dump_members(o, f);
Packit 400c17
	fprintf(f, "}\n");
Packit 400c17
}
Packit 400c17
static void dump_union(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "union %s {\n", o->name);
Packit 400c17
	dump_args(o, f);
Packit 400c17
	fprintf(f, "}\n");
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_enum(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "enum %s {\n", o->name);
Packit 400c17
	dump_members(o, f);
Packit 400c17
	fprintf(f, "}\n");
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_func(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "func %s (\n", o->name);
Packit 400c17
	dump_args(o, f);
Packit 400c17
	fprintf(f, ")\n");
Packit 400c17
Packit 400c17
	obj_dump(o->ptr, f);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_ptr(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "* ");
Packit 400c17
	obj_dump(o->ptr, f);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_typedef(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "typedef %s\n", o->name);
Packit 400c17
	obj_dump(o->ptr, f);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_array(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "[%lu]", o->index);
Packit 400c17
	obj_dump(o->ptr, f);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_var(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "var %s ", o->name);
Packit 400c17
	obj_dump(o->ptr, f);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_struct_member(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "0x%lx", o->offset);
Packit 400c17
	if (o->is_bitfield)
Packit 400c17
		fprintf(f, ":%d-%d", o->first_bit, o->last_bit);
Packit 400c17
Packit 400c17
	if (o->alignment != 0)
Packit 400c17
		fprintf(f, " %u", o->alignment);
Packit 400c17
Packit 400c17
	fprintf(f, " %s ", o->name);
Packit 400c17
	obj_dump(o->ptr, f);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_qualifier(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "%s ", o->base_type);
Packit 400c17
	obj_dump(o->ptr, f);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_base(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	char *type = o->base_type;
Packit 400c17
Packit 400c17
	/* variable args (...) is a special base case */
Packit 400c17
	if (type[0] == '.')
Packit 400c17
		fprintf(f, "%s\n", o->base_type);
Packit 400c17
	else
Packit 400c17
		fprintf(f, "\"%s\"\n", o->base_type);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_constant(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fprintf(f, "%s = 0x%lx\n", o->name, o->constant);
Packit 400c17
}
Packit 400c17
Packit 400c17
static void dump_fail(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	fail("Dump call for this type unsupported!\n");
Packit 400c17
}
Packit 400c17
Packit 400c17
struct dumper {
Packit 400c17
	void (*dumper)(obj_t *o, FILE *f);
Packit 400c17
};
Packit 400c17
Packit 400c17
static struct dumper dumpers[] = {
Packit 400c17
	[__type_reffile].dumper = dump_reffile,
Packit 400c17
	[__type_struct].dumper = dump_struct,
Packit 400c17
	[__type_union].dumper = dump_union,
Packit 400c17
	[__type_enum].dumper = dump_enum,
Packit 400c17
	[__type_func].dumper = dump_func,
Packit 400c17
	[__type_ptr].dumper = dump_ptr,
Packit 400c17
	[__type_typedef].dumper = dump_typedef,
Packit 400c17
	[__type_array].dumper = dump_array,
Packit 400c17
	[__type_var].dumper = dump_var,
Packit 400c17
	[__type_struct_member].dumper = dump_struct_member,
Packit 400c17
	[__type_qualifier].dumper = dump_qualifier,
Packit 400c17
	[__type_base].dumper = dump_base,
Packit 400c17
	[__type_constant].dumper = dump_constant,
Packit 400c17
	[__type_assembly].dumper = dump_fail,
Packit 400c17
	[__type_weak].dumper = dump_fail,
Packit 400c17
};
Packit 400c17
Packit 400c17
void obj_dump(obj_t *o, FILE *f)
Packit 400c17
{
Packit 400c17
	if (o == NULL)
Packit 400c17
		return;
Packit 400c17
Packit 400c17
	if (o->type >= NR_OBJ_TYPES)
Packit 400c17
		fail("Wrong object type %d", o->type);
Packit 400c17
Packit 400c17
	dumpers[o->type].dumper(o, f);
Packit 400c17
}