view leo-obj/tool/richsym.c @ 144:fd772de226cb

tiobjd: started implementing rich symbolic info parsing
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Mon, 28 Apr 2014 08:04:39 +0000
parents
children 25d3ead621f8
line wrap: on
line source

/*
 * Code for working with the "rich" symbolic info
 * present in TI's GPF libraries
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "intstruct.h"
#include "coffconst.h"
#include "globals.h"

extern unsigned get_u16(), get_u32();
extern char *storage_class_to_string();

static int
try_typedef_hack(struct_sym)
	struct internal_syment *struct_sym;
{
	unsigned tpdef_cand;
	struct internal_syment *tpdef_sym;

	if (!struct_sym->aux)
		return(0);
	tpdef_cand = get_u32(struct_sym->aux + 12);
	if (tpdef_cand >= nsymtab)
		return(0);
	tpdef_sym = symtab[tpdef_cand];
	if (!tpdef_sym)
		return(0);
	if (tpdef_sym->class != C_TPDEF)
		return(0);
	if (tpdef_sym->type != struct_sym->type)
		return(0);
	if (tpdef_sym->name[0] != '_')
		return(0);
	if (!tpdef_sym->aux)
		return(0);
	if (get_u32(tpdef_sym->aux) != struct_sym->number)
		return(0);
	struct_sym->struct_name = tpdef_sym->name + 1;
	return(1);
}

static void
preen_strtag_sym(sym, kw, expect_type)
	struct internal_syment *sym;
	char *kw;
{
	char *buf;
	int isund, len;

	isund = (sym->name[0] == '_');
	len = strlen(kw) + 1 + strlen(sym->name) + 1;
	if (isund)
		len--;
	else
		len += 2;
	buf = malloc(len);
	if (!buf) {
		perror("malloc");
		exit(1);
	}
	if (isund)
		sprintf(buf, "%s %s", kw, sym->name + 1);
	else
		sprintf(buf, "%s \"%s\"", kw, sym->name);
	sym->struct_name = buf;
	sym->struct_name_raw = buf;
	if (sym->type != expect_type) {
		fprintf(stderr,
			"warning: type/class mismatch on tag symbol #%u\n",
			sym->number);
		return;
	}
	if (isund)
		return;
	try_typedef_hack(sym);
}

richsym_initial_preen()
{
	unsigned n;
	struct internal_syment *sym;

	for (n = 0; n < nsymtab; n++) {
		sym = symtab[n];
		if (!sym)
			continue;
		switch (sym->class) {
		case C_STRTAG:
			preen_strtag_sym(sym, "struct", T_STRUCT);
			continue;
		case C_UNTAG:
			preen_strtag_sym(sym, "union", T_UNION);
			continue;
		case C_ENTAG:
			preen_strtag_sym(sym, "enum", T_ENUM);
			continue;
		}
	}
}

char *
get_struct_type_name(idx, expect_class, is_typedef)
	unsigned idx;
{
	struct internal_syment *sym;

	if (idx >= nsymtab) {
inv_idx:	fprintf(stderr,
			"error: ref to invalid syment #%u for struct tag\n",
			idx);
		exit(1);
	}
	sym = symtab[idx];
	if (!sym)
		goto inv_idx;
	if (sym->class != expect_class) {
		fprintf(stderr,
		"error: ref to syment #%u for struct tag, class != %s\n",
			idx, storage_class_to_string(expect_class, 0));
		exit(1);
	}
	if (is_typedef)
		return(sym->struct_name_raw);
	else
		return(sym->struct_name);
}

char *
get_base_type_of_syment(sym, is_typedef)
	struct internal_syment *sym;
{
	switch (sym->type & 0xF) {
	case T_VOID:
		return("void");
	case T_CHAR:
		if (is_typedef)
			return("signed char");
		else
			return("char");
	case T_SHORT:
		return("short");
	case T_INT:
		return("int");
	case T_LONG:
		return("long");
	case T_FLOAT:
		return("float");
	case T_DOUBLE:
		return("double");
	case T_STRUCT:
		return get_struct_type_name(get_u32(sym->aux), C_STRTAG,
						is_typedef);
	case T_UNION:
		return get_struct_type_name(get_u32(sym->aux), C_UNTAG,
						is_typedef);
	case T_ENUM:
		return get_struct_type_name(get_u32(sym->aux), C_ENTAG,
						is_typedef);
	case T_UCHAR:
		if (is_typedef)
			return("unsigned char");
		else
			return("u_char");
	case T_USHORT:
		if (is_typedef)
			return("unsigned short");
		else
			return("u_short");
	case T_UINT:
		return("unsigned");
	case T_ULONG:
		if (is_typedef)
			return("unsigned long");
		else
			return("u_long");
	default:
		return("__unknown_base_type");
	}
}