view leo-obj/tool/richsym.c @ 148:13cc7e19ecec

tiobjd disasm -g: support -b as well
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Tue, 29 Apr 2014 06:45:45 +0000
parents 70631c246df0
children fdf3137c703a
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();

int richsym_print_bitsize;

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");
	}
}

richsym_print_in_c(prefix, sym, is_typedef)
	char *prefix;
	struct internal_syment *sym;
{
	char *base_type, *s1, *s2;
	int dertype, last_ptr, narray;

	base_type = get_base_type_of_syment(sym, is_typedef);
	dertype = sym->type >> 4;
	s1 = malloc(strlen(sym->name));
	if (!s1) {
		perror("malloc");
		exit(1);
	}
	strcpy(s1, sym->name + 1);
	last_ptr = 0;
	narray = 0;
	for (; dertype; dertype >>= 2) {
		switch (dertype & 3) {
		case DT_NON:
			fprintf(stderr,
		"error: symbol #%u: DT_NON followed by more derived types\n",
				sym->number);
			exit(1);
		case DT_PTR:
			s2 = malloc(strlen(s1) + 2);
			if (!s2) {
				perror("malloc");
				exit(1);
			}
			sprintf(s2, "*%s", s1);
			free(s1);
			s1 = s2;
			last_ptr = 1;
			continue;
		}
		if (last_ptr) {
			s2 = malloc(strlen(s1) + 3);
			if (!s2) {
				perror("malloc");
				exit(1);
			}
			sprintf(s2, "(%s)", s1);
			free(s1);
			s1 = s2;
		}
		switch (dertype & 3) {
		case DT_FCN:
			s2 = malloc(strlen(s1) + 3);
			if (!s2) {
				perror("malloc");
				exit(1);
			}
			sprintf(s2, "%s()", s1);
			free(s1);
			s1 = s2;
			break;
		case DT_ARY:
			if (narray >= 4) {
				fprintf(stderr,
				"error: symbol #%u: too many [] types\n",
					sym->number);
				exit(1);
			}
			s2 = malloc(strlen(s1) + 8);
			if (!s2) {
				perror("malloc");
				exit(1);
			}
			sprintf(s2, "%s[%u]", s1,
				get_u16(sym->aux + 8 + narray * 2));
			free(s1);
			s1 = s2;
			narray++;
			break;
		default:
			fprintf(stderr,
			"BUG in richsym_print_in_c(): bad derived type\n");
			exit(1);
		}
		last_ptr = 0;
	}
	printf("%s%s %s;", prefix, base_type, s1);
	free(s1);
	if (richsym_print_bitsize && (sym->type & 0x30) != 0x20)
		printf("\t/* %u bits */", get_u32(sym->aux + 4));
	putchar('\n');
}

cmd_ctypes(argc, argv)
	char **argv;
{
	int c;
	unsigned n;
	struct internal_syment *sym;

	while ((c = getopt(argc, argv, "b")) != EOF)
		switch (c) {
		case 'b':
			richsym_print_bitsize++;
			continue;
		default:
			/* error msg already printed */
			exit(1);
		}

	get_int_section_table();
	get_int_symbol_table();
	richsym_initial_preen();
	for (n = 0; n < nsymtab; n++) {
		sym = symtab[n];
		if (!sym)
			continue;
		switch (sym->class) {
		case C_FILE:
			printf("/* from %s */\n", sym->name);
			continue;
		case C_STRTAG:
		case C_UNTAG:
		case C_ENTAG:
			printf("%s {", sym->struct_name_raw);
			if (richsym_print_bitsize && sym->aux)
				printf("\t/* %u bits */", get_u32(sym->aux+4));
			putchar('\n');
			continue;
		case C_EOS:
			fputs("};", stdout);
			if (richsym_print_bitsize && sym->aux)
				printf("\t/* %u bits */", get_u32(sym->aux+4));
			putchar('\n');
			continue;
		case C_MOS:
		case C_MOU:
		case C_MOE:
		case C_TPDEF:
			break;
		default:
			continue;
		}
		if (sym->name[0] != '_') {
			printf(
		"/* symbol #%u of class %s has no leading underscore */\n",
				sym->number,
				storage_class_to_string(sym->class, 0));
			continue;
		}
		if (!sym->aux && sym->class != C_MOE) {
			printf(
			"/* symbol #%u of class %s has no aux record */\n",
				sym->number,
				storage_class_to_string(sym->class, 0));
			continue;
		}
		switch (sym->class) {
		case C_MOS:
		case C_MOU:
			if (sym->scnum != -1)
				printf("\t/* MOS/MOU section != ABS! */\n");
			else if (richsym_print_bitsize >= 2)
				printf("\t/* offset: %u bits */\n", sym->value);
			richsym_print_in_c("\t", sym, 0);
			continue;
		case C_MOE:
			if (sym->scnum != -1) {
				printf("\t/* MOE section != ABS! */\n");
				continue;
			}
			printf("\t%s = %u;", sym->name + 1, sym->value);
			if (sym->value >= 10)
				printf("\t/* 0x%x */", sym->value);
			putchar('\n');
			continue;
		case C_TPDEF:
			richsym_print_in_c("typedef ", sym,
						!(sym->type & 0xFFF0));
			continue;
		}
	}
	exit(0);
}