perfect_dark/tools/mkrom/map.c

152 lines
3.2 KiB
C

#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mkrom.h"
/**
* This file handles reading and parsing the linker map.
*/
extern struct state state;
void map_open(char *filename)
{
state.mapfd = fopen(filename, "r");
if (!state.mapfd) {
fprintf(stderr, "Unable to open map file \"%s\" for reading\n", filename);
exit(1);
}
}
/**
* Find the start and end offsets of the given function in the ROM and write
* their offsets to the start and end pointers.
*
* Return true if the function was found, false if not.
*/
bool map_get_function_rompos(char *funcname, uint32_t *start, uint32_t *end)
{
char line[1024];
char *ptr;
uint32_t segramaddr = 0;
uint32_t segromoffset = 0;
uint32_t ramaddr;
char find[1024];
bool lookingforend = false;
snprintf(find, sizeof(find), " %s\n", funcname);
fseek(state.mapfd, 0, SEEK_SET);
while (!feof(state.mapfd)) {
fgets(line, 1024, state.mapfd);
if (lookingforend) {
ptr = line;
while (isspace(*ptr)) {
ptr++;
}
if (ptr[0] == '0' && ptr[1] == 'x') {
ramaddr = strtoul(ptr, NULL, 16);
*end = ramaddr - segramaddr + segromoffset;
return true;
}
} else if (line[0] == '.') {
// Start of a segment
// ".game 0x000000007f000000 0x1b99e0 load address 0x00000000020ac170"
// Jump to RAM address
ptr = strstr(line, "0x");
segramaddr = strtoul(ptr, NULL, 16);
// Jump to length
ptr++;
ptr = strstr(ptr, "0x");
// Jump to ROM offset
ptr++;
ptr = strstr(ptr, "0x");
segromoffset = strtoul(ptr, NULL, 16);
} else if (strstr(line, find)) {
// Found the function
// "0x000000007f15d9a8 bgInflate"
ptr = strstr(line, "0x");
ramaddr = strtoul(ptr, NULL, 16);
*start = ramaddr - segramaddr + segromoffset;
lookingforend = true;
}
}
fprintf(stderr, "Unable to find function \"%s\" in linker map\n", funcname);
return false;
}
/**
* Find the start and end offsets of the given segment in the ROM and write
* their offsets to the start and end pointers.
*
* Either point may be NULL.
*
* Return true if the segment was found, false if not.
*/
bool map_get_segment_rompos(char *segname, uint32_t *start, uint32_t *end)
{
char startstring[64];
char endstring[64];
char line[1024];
bool found_start = false;
bool found_end = false;
snprintf(startstring, sizeof(startstring), "_%sSegmentRomStart = ", segname);
snprintf(endstring, sizeof(endstring), "_%sSegmentRomEnd = ", segname);
fseek(state.mapfd, 0, SEEK_SET);
// Find lines like this:
// " 0x0000000000001050 _libzipSegmentRomStart = __rompos"
while (!feof(state.mapfd)) {
fgets(line, 1024, state.mapfd);
if (!found_start && strstr(line, startstring)) {
char *ptr = strstr(line, "0x");
if (start != NULL) {
*start = strtoul(ptr, NULL, 16);
}
if (found_end) {
return true;
}
found_start = true;
}
if (!found_end && strstr(line, endstring)) {
char *ptr = strstr(line, "0x");
if (end != NULL) {
*end = strtoul(ptr, NULL, 16);
}
if (found_start) {
return true;
}
found_end = true;
}
}
fprintf(stderr, "Unable to find segment \"%s\" in linker map\n", segname);
return false;
}