OSDev

для всех
Текущее время: 24 апр 2024, 01:17

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ 1 сообщение ] 
Автор Сообщение
 Заголовок сообщения: Backtrace для elf
СообщениеДобавлено: 05 июл 2007, 21:10 

Зарегистрирован: 26 апр 2007, 16:22
Сообщения: 67
Я столкнулся с непонятной багой, из-за которой иногда (примерно раз на 50 запусков) ось падала при загрузке. По EIP вычислил, что падает на long jump'e, который был вынесен в отдельную функцию => невозможно было определить, откуда именно он был вызван.
В результате я написал функцию, которая вытаскивает из стека функции и находит им соответствия в .symtab загруженного elf-файла. Проще говоря, пишет, что и когда вызывалось.
Код
Код:
//    This file is part of the Story OS
//    Copyright (C) 2007  Peter Zotov
//
//    Story OS 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 of the License, or
//    (at your option) any later version.
//
//    Story OS 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 this program; if not, write to the Free Software Foundation, Inc.,
//    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

//alghorytm based on OSKit FreeBSD glue code - stack_trace.c
#include <hal.h>#include <elf.h>#include <multiboot.h>#include <string.h>#include <kprintf.h>

struct _symtab
{
Elf32_Sym* symbols;
unsigned int strings;
unsigned int length;
};

struct _function
{
char* name;
unsigned int address;
};

_symtab null = { NULL, 0, 0 };

multiboot_info_t* get_multiboot_info()
{
return hal->mbi;
}

void* get_user_elf_image()
{
return hal->taskman->current->image;
}

_symtab get_user_symtab()
{
_symtab s;
s.length = 0;

Elf32_Ehdr* header = (Elf32_Ehdr*) get_user_elf_image();
Elf32_Sym* symbols;

if(header == NULL)
 return s;

Elf32_Shdr* hdr = (Elf32_Shdr*) ((unsigned int) get_user_elf_image() + (unsigned int) header->e_shoff);
Elf32_Shdr* symtab = NULL;
Elf32_Shdr* shstrtab = &hdr[header->e_shstrndx]; //it says where is .shstrtab
Elf32_Shdr* strtab = NULL;

for(int i = 0; i < header->e_shnum; i++) //find .symtab
 if(hdr[i].sh_type == SHT_SYMTAB)
  symtab = &hdr[i];
if(!symtab)
 return s;

for(int i = 0; i < header->e_shnum; i++) //find .strtab
 if(hdr[i].sh_type == SHT_STRTAB && strcmp((char*) ((unsigned int) get_user_elf_image() + shstrtab->sh_offset + hdr[i].sh_name), ".strtab") == 0)
  strtab = &hdr[i];
if(!strtab)
 return s;

s.strings = (unsigned int) get_user_elf_image() + strtab->sh_offset;
s.symbols = (Elf32_Sym*) ((unsigned int) get_user_elf_image() + symtab->sh_offset); //symbol table
s.length = symtab->sh_size / sizeof(Elf32_Sym);

return s;
}

_symtab get_kernel_symtab()
{
multiboot_info_t* mbi = get_multiboot_info();
Elf32_Sym* symbols;

Elf32_Shdr* hdr = (Elf32_Shdr*) mbi->u.elf_sec.addr;
Elf32_Shdr* symtab = NULL;
Elf32_Shdr* shstrtab = &hdr[mbi->u.elf_sec.shndx]; //grub says where is .shstrtab
Elf32_Shdr* strtab = NULL;

for(int i = 0; i < mbi->u.elf_sec.num; i++) //find .symtab
 if(hdr[i].sh_type == SHT_SYMTAB)
  symtab = &hdr[i];

for(int i = 0; i < mbi->u.elf_sec.num; i++) //find .strtab
 if(hdr[i].sh_type == SHT_STRTAB && strcmp((char*) (shstrtab->sh_addr + hdr[i].sh_name), ".strtab") == 0)
  strtab = &hdr[i];

_symtab s;
s.strings = strtab->sh_addr;
s.symbols = (Elf32_Sym*) symtab->sh_addr; //symbol table
s.length = symtab->sh_size / sizeof(Elf32_Sym);

return s;
}

_function get_function(_symtab symtab, unsigned int address)
{
_function f;
f.name = NULL;
f.address = 0;
for(int i = 0; i < symtab.length; i++)
 {
 unsigned char type = symtab.symbols[i].st_info & 0xf;
 if(type == STT_SECTION || type == STT_NOTYPE || type == STT_OBJECT || type == STT_FILE)
  continue;
 if(symtab.symbols[i].st_value < address && address < symtab.symbols[i].st_value + symtab.symbols[i].st_size)
  {
  f.name = (char*) (symtab.strings + symtab.symbols[i].st_name);
  f.address = symtab.symbols[i].st_value;
  break;
  }
 }
return f;
}

void _backtrace(_symtab tab1, _symtab tab2)
{
unsigned int *fp, i, address;

asm volatile ("movl %%ebp, %0" : "=r" (fp));

printf("    Backtrace:n");

for (i = 0; i < 17; i++)
 {
 fp = (unsigned int *)(*fp);
 if (!(*(fp + 1) && *fp))
  break;
 address = *(fp + 1);
 
 _function f;
 f.address = 0;
 if(tab1.length)
  f = get_function(tab1, address);
 if(tab2.length && !f.address)
  f = get_function(tab2, address);
 
 if(f.name != 0)
  printf("  %x: [<%X>] %s+0x%xn", i, address, f.name, address - f.address);
 else
  printf("  %x: [<%X>] (unknown)n", i, address);
 }
printf(" =============================n");
}

void user_backtrace()
{
_backtrace(get_kernel_symtab(), get_user_symtab());
}

void raw_backtrace()
{
_backtrace(null, null);
}

void kernel_backtrace()
{
_backtrace(get_kernel_symtab(), null);
}

В нем нужно изменить функцию get_multiboot_info() так, чтобы она возвращала структуру multiboot_info_t, которую при загрузке передает GRUB ядру, и get_user_elf_image так, чтобы она указывала на начало образа elf-файла текущего процесса, или возвращала NULL, если такового не имеется.
После этого, например, можно установить вызов user_backtrace() в обработчик ошибки 0xE, если это пользовательская задача, или kernel_backtrace(), если ядро.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ 1 сообщение ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB