Blame objects.c

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