|
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 |
}
|