view leo-obj/tool/profile.c @ 399:81cda18b0487

compal: move all bootloader analysis work into boot subdir
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 14 Jan 2023 06:17:56 +0000
parents 87b82398a08b
children
line wrap: on
line source

/*
 * It is handy to have a "profile" of what functions and variables
 * a given module defines (presents to the rest of the fw) and what
 * it references.  This profile is constructed from the symbol table.
 *
 * Experience indicates that the order of these symbols in the
 * artifact symtab is often "random", and an alphabetic sort is
 * expected to improve readability.  This module contains the
 * messy code.
 */

#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"

static int
is_symbol_text_def(sym)
	struct internal_syment *sym;
{
	if (!sym->section)
		return(0);
	if (!strncmp(sym->section->name, ".text", 5))
		return(1);
	else
		return(0);
}

static int
is_symbol_nontext_def(sym)
	struct internal_syment *sym;
{
	if (!sym->section)
		return(0);
	if (!strncmp(sym->section->name, ".text", 5))
		return(0);
	else
		return(1);
}

static int
is_symbol_extref(sym)
	struct internal_syment *sym;
{
	if (sym->section)
		return(0);
	else
		return(1);
}

static int
compare_for_sort(p1, p2)
	struct internal_syment **p1, **p2;
{
	return strcmp((*p1)->name, (*p2)->name);
}

static void
list_class(firstidx, lastidx, total, checkfunc, printsec)
	unsigned firstidx, lastidx, total;
	int (*checkfunc)();
{
	struct internal_syment **array, *sym;
	unsigned n, m;

	array = malloc(sizeof(void *) * total);
	if (!array) {
		perror("malloc");
		exit(1);
	}
	m = 0;
	for (n = firstidx; n <= lastidx; n++) {
		sym = symtab[n];
		if (!sym)
			continue;
		if (sym->class != C_EXT)
			continue;
		if (!checkfunc(sym))
			continue;
		array[m++] = sym;
	}
	if (m != total) {
		fprintf(stderr, "BUG: symbol class miscount in profile gen\n");
		exit(1);
	}
	qsort(array, total, sizeof(void *), compare_for_sort);
	for (n = 0; n < total; n++) {
		sym = array[n];
		if (printsec)
			printf("%s (%s)\n", sym->name, sym->section->name);
		else
			printf("%s\n", sym->name);
	}
	free(array);
	putchar('\n');
}

extern_profile_report(heading)
	char *heading;
{
	unsigned n;
	int first_extern = -1, last_extern;
	struct internal_syment *sym;
	unsigned defs_text = 0, defs_nontext = 0, extrefs = 0;

	for (n = 0; n < nsymtab; n++) {
		sym = symtab[n];
		if (!sym)
			continue;
		if (sym->class != C_EXT)
			continue;
		if (first_extern < 0)
			first_extern = n;
		last_extern = n;
		if (sym->scnum < 0) {
			fprintf(stderr,
		"symbol entry #%u: unexpected negative scnum for C_EXT\n", n);
			exit(1);
		}
		if (sym->scnum == 0)
			extrefs++;
		else if (!strncmp(sym->section->name, ".text", 5))
			defs_text++;
		else
			defs_nontext++;
	}
	if (first_extern < 0) {
		printf("%s has no external symbols!\n", heading);
		return(1);
	}
	if (defs_text || defs_nontext) {
		printf("%s defines:\n\n", heading);
		if (defs_text)
			list_class(first_extern, last_extern, defs_text,
					is_symbol_text_def, 1);
		if (defs_nontext)
			list_class(first_extern, last_extern, defs_nontext,
					is_symbol_nontext_def, 1);
	}
	if (extrefs) {
		printf("%s references:\n\n", heading);
		list_class(first_extern, last_extern, extrefs,
				is_symbol_extref, 0);
	}
	return(0);
}

cmd_profile()
{
	get_int_section_table();
	get_int_symbol_table();
	extern_profile_report(objfilename);
	exit(0);
}