OSDev http://osdev.su/ |
|
Backtrace для elf http://osdev.su/viewtopic.php?f=6&t=80 |
Страница 1 из 1 |
Автор: | whitequark [ 05 июл 2007, 21:10 ] |
Заголовок сообщения: | Backtrace для elf |
Я столкнулся с непонятной багой, из-за которой иногда (примерно раз на 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 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |