/* Map file generation
Copyright (C) 2003, 2004, 2005
Craig Franklin
This file is part of gputils.
gputils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
gputils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with gputils; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "stdhdr.h"
#include "libgputils.h"
#include "gplink.h"
#include "map.h"
#ifdef STDC_HEADERS
#include <stdarg.h>
#endif
#define SECTION_UNKNOWN 0
#define SECTION_ROMDATA 1
#define SECTION_CODE 2
#define SECTION_IDATA 3
#define SECTION_UDATA 4
/* FIXME: Sort symbols by name and size. */
void
map_line(const char *format, ...)
{
va_list args;
char buffer[BUFSIZ];
if (state.map.f == NULL)
return;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
fprintf(state.map.f, "%s\n", buffer);
return;
}
static int
_section_value(gp_section_type *section)
{
int value = 0;
if ((section->flags & STYP_TEXT) ||
(section->flags & STYP_DATA_ROM)) {
value = SECTION_CODE;
} else if (section->flags & STYP_DATA) {
value = SECTION_IDATA;
} else if ((section->flags & STYP_BSS) ||
(section->flags & STYP_OVERLAY)) {
value = SECTION_UDATA;
} else if (section->flags & STYP_DATA_ROM) {
value = SECTION_ROMDATA;
} else {
value = SECTION_UNKNOWN;
}
return value;
}
static int
compare_sections(const void *a, const void *b)
{
gp_section_type *section_a = *((gp_section_type **)a);
gp_section_type *section_b = *((gp_section_type **)b);
int value_a = _section_value(section_a);
int value_b = _section_value(section_b);
if (value_a < value_b)
return -1;
if (value_a > value_b)
return +1;
if (section_a->address < section_b->address)
return -1;
if (section_a->address > section_b->address)
return +1;
return 0;
}
static void
_write_sections(void)
{
gp_section_type *section = NULL;
gp_section_type **section_list = NULL;
char *type;
char *location;
long i;
section_list = malloc(sizeof(gp_section_type *) * state.object->num_sections);
if (!section_list) {
fprintf(stderr, "error: out of memory\n");
exit(1);
}
section = state.object->sections;
for (i = 0; i < state.object->num_sections; i++) {
assert(section != NULL);
section_list[i] = section;
section = section->next;
}
qsort((void *)section_list,
state.object->num_sections,
sizeof(gp_section_type *),
compare_sections);
map_line(" Section Info");
map_line(" Section Type Address Location Size(Bytes)");
map_line(" --------- --------- --------- --------- ---------");
for (i = 0; i < state.object->num_sections; i++) {
section = section_list[i];
switch (_section_value(section)) {
case SECTION_ROMDATA:
type = "romdata";
break;
case SECTION_CODE:
type = "code";
break;
case SECTION_IDATA:
type = "idata";
break;
case SECTION_UDATA:
type = "udata";
break;
case SECTION_UNKNOWN:
default:
type = "UNKNOWN";
}
if ((section->flags & STYP_TEXT) ||
(section->flags & STYP_DATA_ROM)) {
location = "program";
} else {
location = "data";
}
assert(section->name != NULL);
if (section->size != 0) {
map_line("%25s %10s %#08x %10s %#08x",
section->name,
type,
section->address,
location,
section->size);
}
}
map_line(" ");
return;
}
static void
_write_program_memory(void)
{
gp_section_type *section = NULL;
int size;
int prog_size = 0;
map_line(" Program Memory Usage");
map_line(" Start End");
map_line(" --------- ---------");
section = state.object->sections;
while (section != NULL) {
if (((section->flags & STYP_TEXT) ||
(section->flags & STYP_DATA_ROM)) && (section->size != 0)) {
if (state.object->class == PROC_CLASS_PIC16E) {
size = section->size;
} else {
size = section->size >> 1;
}
map_line(" %#08x %#08x",
section->address,
section->address + size - 1);
prog_size += size;
}
section = section->next;
}
if (state.object->class == PROC_CLASS_PIC16E) {
prog_size >>= 1;
}
map_line(" ");
map_line(" %i program addresses used",
prog_size);
map_line(" ");
}
struct file_stack {
gp_symbol_type *symbol;
struct file_stack *previous;
};
static struct file_stack *
push_file(struct file_stack *stack, gp_symbol_type *symbol)
{
struct file_stack *new;
/* allocate memory for the new stack */
new = (struct file_stack *)malloc(sizeof(*new));
new->previous = stack;
new->symbol = symbol;
return new;
}
static struct file_stack *
pop_file(struct file_stack *stack)
{
struct file_stack *old;
if (stack) {
old = stack;
stack = stack->previous;
free(old);
}
return stack;
}
static void
_write_symbols(void)
{
struct file_stack *stack = NULL;
gp_symbol_type *file = NULL;
gp_symbol_type *symbol = NULL;
char *location;
char *storage;
char *file_name;
map_line(" Symbols");
map_line(" Name Address Location Storage File");
map_line(" --------- --------- --------- --------- ---------");
symbol = state.object->symbols;
while (symbol != NULL) {
if (symbol->class == C_FILE) {
stack = push_file(stack, symbol);
} else if (symbol->class == C_EOF) {
stack = pop_file(stack);
} else if ((symbol->section_number > 0) &&
(symbol->class != C_SECTION)) {
if (stack == NULL) {
/* the symbol is not between a .file/.eof pair */
file_name = " ";
} else {
file = stack->symbol;
assert(file != NULL);
assert(file->aux_list != NULL);
file_name = file->aux_list->_aux_symbol._aux_file.filename;
}
assert(symbol->section != NULL);
assert(symbol->name != NULL);
if ((symbol->section->flags & STYP_TEXT) ||
(symbol->section->flags & STYP_DATA_ROM)) {
location = "program";
} else {
location = "data";
}
if (symbol->class == C_EXT) {
storage = "extern";
} else {
storage = "static";
}
map_line("%25s %#08x %10s %10s %s",
symbol->name,
symbol->value,
location,
storage,
file_name);
}
symbol = symbol->next;
}
map_line(" ");
}
void
make_map(void)
{
if ((gp_num_errors) || (state.mapfile == suppress)) {
unlink(state.mapfilename);
return;
}
state.map.f = fopen(state.mapfilename, "wt");
if (state.map.f == NULL) {
perror(state.mapfilename);
exit(1);
}
map_line("%s", GPLINK_VERSION_STRING);
map_line("Map File - Created %s", state.startdate);
map_line(" ");
/* write sections */
_write_sections();
/* program memory usage */
_write_program_memory();
/* write symbols */
_write_symbols();
fclose(state.map.f);
}
syntax highlighted by Code2HTML, v. 0.9.1