📄 elfcore.c
字号:
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: ELF core file debug support.
*
****************************************************************************/
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "trpimp.h"
#include "exeelf.h"
#include "mad.h"
#include "madregs.h"
#include "elfcore.h"
/* This file contains a platform-independent superstructure. All
* platform and architecture specific details are handled
* by target-specific "drivers".
*
* Note: We do not worry about segments in this trap file since
* ELF does not support segmented architectures. Makes life easier.
*/
/* Somewhat arbitrary path limit */
#define MAX_FULLPATH_LEN 500
#define ELF_ROUND (sizeof( Elf32_Word ) - 1)
#define NO_FILE (-1)
static plat_drv_t *drivers[] = {
&Drv_FreeBSD,
&Drv_Neutrino,
NULL
};
extern unsigned FindFilePath( int exe, char *name, char *result );
enum {
MH_NONE,
MH_DEBUGGEE,
MH_SLIB,
MH_PROC
};
struct {
unsigned loaded : 1;
unsigned x_loaded : 1;
unsigned ignore_timestamp : 1;
unsigned mapping_shared : 1;
unsigned swap_bytes : 1;
int err_no;
int fd; /* core file descriptor */
Elf32_Ehdr *c_ehdr; /* core file ELF header */
Elf32_Phdr *c_phdr; /* core file program header */
int x_fd; /* executable file descriptor */
Elf32_Ehdr *x_ehdr; /* executable ELF header */
Elf32_Phdr *x_phdr; /* executable program header */
plat_drv_t *plat; /* platform-specific driver */
void *ctx; /* driver-specific context data */
char exe_name[MAX_FULLPATH_LEN];
} Core;
/* Read ELF header and check if it's roughly what we're expecting */
int elf_read_hdr( int fd, Elf32_Ehdr *e_hdr )
{
int result = FALSE;
lseek( fd, 0, SEEK_SET );
if( read( fd, e_hdr, sizeof( *e_hdr ) ) >= sizeof( *e_hdr ) &&
memcmp( e_hdr->e_ident, ELF_SIGNATURE, 4 ) == 0 &&
e_hdr->e_ident[EI_CLASS] == ELFCLASS32) {
#ifdef __BIG_ENDIAN__
if( e_hdr->e_ident[EI_DATA] == ELFDATA2LSB )
Core.swap_bytes = TRUE;
#else
if( e_hdr->e_ident[EI_DATA] == ELFDATA2MSB )
Core.swap_bytes = TRUE;
#endif
if( Core.swap_bytes ) {
SWAP_16( e_hdr->e_type );
SWAP_16( e_hdr->e_machine );
SWAP_32( e_hdr->e_version );
SWAP_32( e_hdr->e_entry );
SWAP_32( e_hdr->e_phoff );
SWAP_32( e_hdr->e_shoff );
SWAP_32( e_hdr->e_flags );
SWAP_16( e_hdr->e_ehsize );
SWAP_16( e_hdr->e_phentsize );
SWAP_16( e_hdr->e_phnum );
SWAP_16( e_hdr->e_shentsize );
SWAP_16( e_hdr->e_shnum );
SWAP_16( e_hdr->e_shstrndx );
}
if( e_hdr->e_phoff != 0 && e_hdr->e_phentsize >= sizeof( Elf32_Phdr ) ) {
result = TRUE;
}
}
return( result );
}
/* Read ELF program headers */
int elf_read_phdr( int fd, Elf32_Ehdr *e_hdr, Elf32_Phdr **pp_hdr )
{
Elf32_Phdr *e_phdr;
int i;
int result = FALSE;
*pp_hdr = malloc( sizeof( *e_phdr ) * e_hdr->e_phnum );
if( *pp_hdr != NULL ) {
int error = FALSE;
e_phdr = *pp_hdr;
if( lseek( fd, e_hdr->e_phoff, SEEK_SET ) == e_hdr->e_phoff ) {
for( i = 0; i < e_hdr->e_phnum; i++ ) {
if( read( fd, e_phdr, sizeof( *e_phdr ) ) < sizeof( *e_phdr ) ) {
error = TRUE;
break;
}
/* Skip any extra bytes that might be present */
if( lseek( fd, e_hdr->e_phentsize - sizeof( *e_phdr ), SEEK_CUR ) < 0 ) {
error = TRUE;
break;
}
if( Core.swap_bytes ) {
SWAP_32( e_phdr->p_type );
SWAP_32( e_phdr->p_offset );
SWAP_32( e_phdr->p_vaddr );
SWAP_32( e_phdr->p_paddr );
SWAP_32( e_phdr->p_filesz );
SWAP_32( e_phdr->p_memsz );
SWAP_32( e_phdr->p_flags );
SWAP_32( e_phdr->p_align );
}
e_phdr++;
}
}
if( !error ) {
result = TRUE;
}
}
return( result );
}
unsigned ReqGet_sys_config( void )
{
get_sys_config_ret *ret;
int mad, os, cpu, fpu;
ret = GetOutPtr( 0 );
if( Core.loaded && Core.plat->qcfg( Core.ctx, &mad, &os, &cpu, &fpu ) ) {
ret->sys.mad = mad;
ret->sys.os = os;
ret->sys.cpu = cpu;
ret->sys.fpu = fpu;
} else {
ret->sys.mad = MAD_X86;
ret->sys.os = OS_IDUNNO;
ret->sys.cpu = X86_386;
ret->sys.fpu = X86_387;
}
ret->sys.osmajor = 1;
ret->sys.osminor = 0;
ret->sys.huge_shift = 3; // Not relevant for flat model
return( sizeof( *ret ) );
}
unsigned ReqMap_addr( void )
{
map_addr_req *acc;
map_addr_ret *ret;
unsigned index;
unsigned seg;
acc = GetInPtr( 0 );
ret = GetOutPtr( 0 );
ret->lo_bound = 0;
ret->hi_bound = ~(addr48_off)9;
seg = acc->in_addr.segment;
switch( seg ) {
case MAP_FLAT_CODE_SELECTOR:
seg = 0x04;
break;
case MAP_FLAT_DATA_SELECTOR:
seg = 0x0c;
break;
}
ret->out_addr.offset = acc->in_addr.offset;
switch( acc->handle ) {
case MH_DEBUGGEE:
if( acc->in_addr.segment == MAP_FLAT_DATA_SELECTOR ) {
index = 0;
} else {
index = seg >> 3;
}
#if 0
if( Core.loaded ) {
ret->out_addr.offset += Core.segs[ index ].mem_off;
}
#endif
break;
case MH_SLIB:
break;
case MH_PROC:
seg += 0xE0 - 4;
break;
}
ret->out_addr.segment = 0;
return( sizeof( *ret ) );
}
unsigned ReqChecksum_mem( void )
{
checksum_mem_ret *ret;
ret = GetOutPtr( 0 );
ret->result = 0; // Dead programs do not tend to change much
return( sizeof( *ret ) );
}
/* Read data with given virtual address from an ELF executable */
size_t read_from_elf( int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr,
void *buf, addr_off va, size_t len )
{
int i;
for( i = 0; i < ehdr->e_phnum ; ++i, ++phdr ) {
int read_len;
Elf32_Off rel_ofs; // Relative offset within segment
if( phdr->p_type != PT_LOAD ) continue;
if( (va < phdr->p_vaddr) ||
(va > phdr->p_vaddr + phdr->p_memsz - 1) ) {
continue;
}
rel_ofs = va - phdr->p_vaddr;
/* Adjust length if pointing past end of segment */
if( (va + len) > (phdr->p_vaddr + phdr->p_memsz) ) {
len = rel_ofs + len - phdr->p_memsz;
}
read_len = len;
/* Adjust length to read from file if p_memsz > p_filesz */
if( (va + len) > (phdr->p_vaddr + phdr->p_filesz) ) {
read_len = phdr->p_filesz - rel_ofs;
if( read_len < 0 )
read_len = 0;
}
if( len != 0 ) {
if( read_len != 0 ) {
lseek( fd, phdr->p_offset + rel_ofs, SEEK_SET );
read_len = read( fd, buf, read_len );
if( read_len == -1 ) {
return( 0 );
}
}
if( read_len < len ) {
memset( (unsigned_8 *)buf + read_len, 0, len - read_len );
}
}
return( len );
}
return( 0 );
}
unsigned ReqRead_mem( void )
{
read_mem_req *acc;
void *ret;
unsigned len;
acc = GetInPtr( 0 );
ret = GetOutPtr( 0 );
if( !Core.loaded ) {
return( 0 );
}
len = read_from_elf( Core.fd, Core.c_ehdr, Core.c_phdr, ret,
acc->mem_addr.offset, acc->len );
/* If we couldn't read the memory from core, try the executable.
* This is required for FreeBSD core files.
*/
if( len == 0 && (Core.x_fd != NO_FILE) ) {
len = read_from_elf( Core.x_fd, Core.x_ehdr, Core.x_phdr, ret,
acc->mem_addr.offset, acc->len );
}
return( len );
}
/* Functions to write memory and do port I/O don't do anything */
unsigned ReqWrite_mem( void )
{
write_mem_ret *ret;
ret = GetOutPtr( 0 );
ret->len = 0;
return( sizeof( *ret ) );
}
unsigned ReqRead_io( void )
{
return( 0 );
}
unsigned ReqWrite_io( void )
{
write_io_ret *ret;
ret = GetOutPtr( 0 );
ret->len = 0;
return( sizeof( *ret ) );
}
/* Functions to read machine registers must read from core file */
static size_t ReadCPU( mad_registers *r )
{
size_t size = 0;
if( Core.loaded ) {
size = Core.plat->regs( Core.ctx, r, 0 );
}
return( size );
}
static size_t ReadFPU( mad_registers *r )
{
size_t size = 0;
if( Core.loaded ) {
size = Core.plat->regs( Core.ctx, r, 0 );
}
return( size );
}
unsigned ReqRead_cpu( void )
{
return( ReadCPU( GetOutPtr( 0 ) ) );
}
unsigned ReqRead_fpu( void )
{
return( ReadFPU( GetOutPtr( 0 ) ) );
}
unsigned ReqRead_regs( void )
{
mad_registers *mr;
int size;
mr = GetOutPtr( 0 );
size = ReadCPU( mr );
size += ReadFPU( mr );
return( size );
}
/* Functions to write machine registers don't do anything */
unsigned ReqWrite_cpu( void )
{
return( 0 );
}
unsigned ReqWrite_fpu( void )
{
return( 0 );
}
unsigned ReqWrite_regs( void )
{
return( 0 );
}
/* Utility routine to look for a note of given type. If found, will
* return a pointer to its name in memory that caller must free. The
* file pointer will be positioned at the beginning of note data.
*/
char *find_note( int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr,
bool swap, Elf_Note *note )
{
int i;
int ntype = note->n_type;
char *name = NULL;
/* Loop over program headers */
for( i = 0; i < ehdr->e_phnum ; ++i, ++phdr ) {
off_t read_len;
off_t skip;
if( phdr->p_type != PT_NOTE ) continue;
/* We found a note segment, loop over the notes */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -