2018-11-16 14:47:21 +01:00
|
|
|
#include "stack.h"
|
2023-11-20 00:11:47 +01:00
|
|
|
#include "elf.h"
|
2019-05-17 09:35:23 +02:00
|
|
|
#include "klibc.h"
|
2023-11-20 00:11:47 +01:00
|
|
|
#include "paging.h"
|
2020-04-27 00:14:37 +02:00
|
|
|
#include "types.h"
|
2018-11-16 14:47:21 +01:00
|
|
|
|
2023-11-20 00:11:47 +01:00
|
|
|
/** Defined in linker.ld script **/
|
|
|
|
extern char __multiboot_data_start;
|
|
|
|
extern char __multiboot_data_end;
|
|
|
|
static size_t multibootDataSize;
|
|
|
|
static size_t multibootUsage;
|
|
|
|
|
|
|
|
/** Initialized at 'StackSymbolSetup'. */
|
|
|
|
static Elf32_Sym_t *elfSymtab;
|
|
|
|
static size_t elfSymtabSize;
|
|
|
|
|
|
|
|
static const char *elfStrtab;
|
|
|
|
static size_t elfStrtabSize;
|
|
|
|
|
|
|
|
static void *stackSaveSection(const void *addr, size_t size, const char *sectionName)
|
|
|
|
{
|
|
|
|
if (size > (multibootDataSize - multibootUsage)) {
|
|
|
|
printf("No enough room to store %s (%d/%d). Increase multiboot_data section size",
|
|
|
|
sectionName, size, (multibootDataSize - multibootUsage));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
void *destAddr = (void *)&__multiboot_data_start + multibootUsage;
|
|
|
|
|
|
|
|
memcpy((void *)destAddr, addr, size);
|
|
|
|
multibootUsage += size;
|
|
|
|
|
|
|
|
return destAddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copy the symbols table and string table from a multiboot information.
|
|
|
|
* We need to copy them as they are loaded by the bootloader and could be override as soon
|
|
|
|
* as we play with memory around our loaded kernel.
|
|
|
|
* As special ELF section is allocated for this purpose.
|
|
|
|
*/
|
|
|
|
void stackSymbolSetup(multiboot_info_t *mbi)
|
|
|
|
{
|
|
|
|
/** Get the section header table as an array of section headers. */
|
|
|
|
Elf32_Shdr_t *sht = (Elf32_Shdr_t *)mbi->u.elf_sec.addr;
|
|
|
|
size_t sec_len = (size_t)mbi->u.elf_sec.num;
|
|
|
|
assert(mbi->u.elf_sec.size == sizeof(Elf32_Shdr_t));
|
|
|
|
multibootDataSize = &__multiboot_data_end - &__multiboot_data_start;
|
|
|
|
multibootUsage = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The section header at index 'shndx' in the table is a meta section
|
|
|
|
* header. It contains a list of section header names in the table. We
|
|
|
|
* should look for section header names ".symtab" & ".strtab".
|
|
|
|
*/
|
|
|
|
const char *sh_names = (const char *)sht[mbi->u.elf_sec.shndx].sh_addr;
|
|
|
|
|
|
|
|
/** Loop through the table and look for ".symtab" & ".strtab". */
|
|
|
|
for (size_t i = 0; i < sec_len; ++i) {
|
|
|
|
const char *name = sh_names + sht[i].sh_name;
|
|
|
|
|
|
|
|
if (strcmp(name, ".symtab") == 0) {
|
|
|
|
assert(sht[i].sh_type == SHT_SYMTAB);
|
|
|
|
elfSymtab = stackSaveSection((void *)sht[i].sh_addr, sht[i].sh_size, name);
|
|
|
|
if (elfSymtab)
|
|
|
|
elfSymtabSize = sht[i].sh_size;
|
|
|
|
|
|
|
|
} else if (strcmp(name, ".strtab") == 0) {
|
|
|
|
assert(sht[i].sh_type == SHT_STRTAB);
|
|
|
|
elfStrtab = stackSaveSection((void *)sht[i].sh_addr, sht[i].sh_size, name);
|
|
|
|
if (elfStrtab)
|
|
|
|
elfStrtabSize = sht[i].sh_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Look up an address in symbols map and return its function name or NULL. */
|
2024-01-26 22:53:39 +01:00
|
|
|
const char *lookupSymbolName(uint32_t addr)
|
2023-11-20 00:11:47 +01:00
|
|
|
{
|
|
|
|
size_t symtab_len = elfSymtabSize / sizeof(Elf32_Sym_t);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < symtab_len; ++i) {
|
|
|
|
if ((ELF_SYM_TYPE(elfSymtab[i].st_info) == ELF_SYM_TYPE_FUNC) &&
|
|
|
|
(addr >= elfSymtab[i].st_value) &&
|
|
|
|
(addr <= elfSymtab[i].st_value + elfSymtab[i].st_size)) {
|
|
|
|
return elfStrtab + elfSymtab[i].st_name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-19 13:56:19 +01:00
|
|
|
void printStackTrace(unsigned int maxFrames)
|
|
|
|
{
|
2018-11-16 14:47:21 +01:00
|
|
|
#ifdef DEBUG
|
2020-04-27 00:14:37 +02:00
|
|
|
// Now on Stack:
|
|
|
|
// ( potential second function argument )
|
|
|
|
// first function argument (maxFrames)
|
|
|
|
// return address from caller
|
|
|
|
// EBP (Extended Base Pointer) of calling function
|
|
|
|
//
|
|
|
|
// retrace function from address could done by optaining function address with gdb or
|
|
|
|
// objdump -S kernel
|
|
|
|
unsigned int *ebp = __builtin_frame_address(0);
|
|
|
|
for (unsigned int frame = 0; frame < maxFrames; frame++) {
|
2021-11-13 08:31:05 +01:00
|
|
|
unsigned int eip = *(ebp + 1);
|
2020-04-27 00:14:37 +02:00
|
|
|
if (eip == 0) {
|
|
|
|
// No caller on stack
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
unsigned int *arguments = ebp + 2;
|
2023-11-20 00:11:47 +01:00
|
|
|
const char *functionName = lookupSymbolName(eip);
|
|
|
|
if (functionName != NULL) {
|
|
|
|
printf("[%d] %s (", frame, functionName);
|
|
|
|
} else {
|
|
|
|
printf("[%d] 0x%x (", frame, eip);
|
|
|
|
}
|
2020-04-27 00:14:37 +02:00
|
|
|
int nbArg = 0;
|
|
|
|
do {
|
|
|
|
if ((_stack_bottom <= (vaddr_t)arguments) && ((vaddr_t)arguments <= _stack_top)) {
|
|
|
|
printf(" 0x%x", *arguments);
|
|
|
|
arguments += 1;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nbArg++;
|
|
|
|
if (nbArg >= 4) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
printf(")\n");
|
|
|
|
ebp = (unsigned int *)(ebp[0]);
|
|
|
|
}
|
2018-11-16 14:47:21 +01:00
|
|
|
#else
|
2020-04-27 00:14:37 +02:00
|
|
|
printf("Must be compiled with -fno-omit-frame-pointer for full stack\n");
|
|
|
|
unsigned int *ebp = &maxFrames - 2;
|
2023-11-08 20:53:13 +01:00
|
|
|
unsigned int *eip = ebp + sizeof(unsigned int);
|
2023-11-09 20:30:09 +01:00
|
|
|
printf("[0] 0x%x\n", (unsigned int)eip);
|
2018-11-16 14:47:21 +01:00
|
|
|
#endif
|
|
|
|
}
|