diff options
author | eutarass | 2011-01-28 00:50:10 +0000 |
---|---|---|
committer | eutarass | 2011-01-28 00:50:10 +0000 |
commit | d15f56d8dbc8dca49b29be38ba11df89435060da (patch) | |
tree | 7c8488137b23b53be8e9b7afcfd738bd0802464b | |
parent | 6e852da01959d36d39d56512e5e238d73d7a670c (diff) | |
download | org.eclipse.tcf.agent-d15f56d8dbc8dca49b29be38ba11df89435060da.tar.gz org.eclipse.tcf.agent-d15f56d8dbc8dca49b29be38ba11df89435060da.tar.xz org.eclipse.tcf.agent-d15f56d8dbc8dca49b29be38ba11df89435060da.zip |
TCF Agent: DWARF reader: extended support for relocatable ELF files
-rw-r--r-- | machine/i386/elf-mdep.h | 37 | ||||
-rw-r--r-- | services/dwarfio.h | 6 | ||||
-rw-r--r-- | services/dwarfreloc.c | 94 | ||||
-rw-r--r-- | services/runctrl.c | 2 | ||||
-rw-r--r-- | services/symbols_proxy.c | 4 | ||||
-rw-r--r-- | services/tcf_elf.c | 13 | ||||
-rw-r--r-- | services/tcf_elf.h | 18 |
7 files changed, 128 insertions, 46 deletions
diff --git a/machine/i386/elf-mdep.h b/machine/i386/elf-mdep.h index 23e2ce77..6086ba6b 100644 --- a/machine/i386/elf-mdep.h +++ b/machine/i386/elf-mdep.h @@ -21,37 +21,6 @@ #define R_386_PC32 2 static void elf_relocate(void) { - U4_T value = 0; - if (sym_index != STN_UNDEF) { - Elf32_Sym bf = ((Elf32_Sym *)symbols->data)[sym_index]; - if (symbols->file->byte_swap) { - SWAP(bf.st_name); - SWAP(bf.st_value); - SWAP(bf.st_size); - SWAP(bf.st_info); - SWAP(bf.st_other); - SWAP(bf.st_shndx); - } - if (symbols->file->type != ET_EXEC) { - switch (bf.st_shndx) { - case SHN_ABS: - value = bf.st_value; - break; - case SHN_COMMON: - case SHN_UNDEF: - str_exception(ERR_INV_FORMAT, "Invalid relocation record"); - break; - default: - if (bf.st_shndx >= symbols->file->section_cnt) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); - value = (U4_T)(symbols->file->sections + bf.st_shndx)->addr + bf.st_value; - *destination = symbols->file->sections + bf.st_shndx; - break; - } - } - else { - value = bf.st_value; - } - } if (relocs->type == SHT_REL) { U4_T x = *(U4_T *)((char *)section->data + reloc_offset); if (section->file->type != ET_REL) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); @@ -61,16 +30,16 @@ static void elf_relocate(void) { } switch (reloc_type) { case R_386_NONE: - *destination = NULL; + *destination_section = NULL; break; case R_386_32: if (data_size < 4) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); - *(U4_T *)data_buf = value + reloc_addend; + *(U4_T *)data_buf = (U4_T)(sym_value + reloc_addend); if (section->file->byte_swap) SWAP(*(U4_T *)data_buf); break; case R_386_PC32: if (data_size < 4) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); - *(U4_T *)data_buf = (U4_T)(section->addr + reloc_offset) + value + reloc_addend; + *(U4_T *)data_buf = (U4_T)(section->addr + reloc_offset + sym_value + reloc_addend); if (section->file->byte_swap) SWAP(*(U4_T *)data_buf); break; default: diff --git a/services/dwarfio.h b/services/dwarfio.h index 6ad062f8..5a1c7a50 100644 --- a/services/dwarfio.h +++ b/services/dwarfio.h @@ -65,6 +65,12 @@ extern U8_T dio_ReadU8LEB128(void); extern I8_T dio_ReadS8LEB128(void); extern U8_T dio_ReadUX(int Size); + +/* + * Read link-time address value. + * Relocation tables are used if necessary to compute the address value. + * For a file that can be relotated at run-time, 's' is assigned a section that the address points to. + */ extern U8_T dio_ReadAddressX(ELF_Section ** s, int Size); extern U8_T dio_ReadAddress(ELF_Section ** s); diff --git a/services/dwarfreloc.c b/services/dwarfreloc.c index 23089c09..c8d33dbf 100644 --- a/services/dwarfreloc.c +++ b/services/dwarfreloc.c @@ -29,12 +29,13 @@ static ELF_Section * section = NULL; static ELF_Section * relocs = NULL; static ELF_Section * symbols = NULL; -static ELF_Section ** destination = NULL; +static ELF_Section ** destination_section = NULL; static U8_T reloc_offset = 0; static U4_T reloc_type = 0; -static U4_T reloc_addend = 0; +static U8_T reloc_addend = 0; static U4_T sym_index = 0; +static U8_T sym_value = 0; static void * data_buf = NULL; static size_t data_size = 0; @@ -77,10 +78,95 @@ static void relocate(void * r) { reloc_type = ELF32_R_TYPE(bf.r_info); reloc_addend = bf.r_addend; } + if (sym_index != STN_UNDEF) { + Elf32_Sym bf = ((Elf32_Sym *)symbols->data)[sym_index]; + if (symbols->file->byte_swap) { + SWAP(bf.st_name); + SWAP(bf.st_value); + SWAP(bf.st_size); + SWAP(bf.st_info); + SWAP(bf.st_other); + SWAP(bf.st_shndx); + } + if (symbols->file->type != ET_EXEC) { + switch (bf.st_shndx) { + case SHN_ABS: + sym_value = bf.st_value; + break; + case SHN_COMMON: + case SHN_UNDEF: + str_exception(ERR_INV_FORMAT, "Invalid relocation record"); + break; + default: + if (bf.st_shndx >= symbols->file->section_cnt) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); + sym_value = (symbols->file->sections + bf.st_shndx)->addr + bf.st_value; + *destination_section = symbols->file->sections + bf.st_shndx; + break; + } + } + else { + sym_value = bf.st_value; + } + } } else { - str_exception(ERR_INV_FORMAT, "Unsupported ELF relocation type"); + if (relocs->type == SHT_REL) { + Elf64_Rel bf = *(Elf64_Rel *)r; + if (relocs->file->byte_swap) { + SWAP(bf.r_offset); + SWAP(bf.r_info); + } + sym_index = ELF64_R_SYM(bf.r_info); + reloc_type = ELF64_R_TYPE(bf.r_info); + reloc_addend = 0; + } + else { + Elf64_Rela bf = *(Elf64_Rela *)r; + if (relocs->file->byte_swap) { + SWAP(bf.r_offset); + SWAP(bf.r_info); + SWAP(bf.r_addend); + } + sym_index = ELF64_R_SYM(bf.r_info); + reloc_type = ELF64_R_TYPE(bf.r_info); + reloc_addend = bf.r_addend; + } + if (sym_index != STN_UNDEF) { + Elf64_Sym bf = ((Elf64_Sym *)symbols->data)[sym_index]; + if (symbols->file->byte_swap) { + SWAP(bf.st_name); + SWAP(bf.st_value); + SWAP(bf.st_size); + SWAP(bf.st_info); + SWAP(bf.st_other); + SWAP(bf.st_shndx); + } + if (symbols->file->type != ET_EXEC) { + switch (bf.st_shndx) { + case SHN_ABS: + sym_value = bf.st_value; + break; + case SHN_COMMON: + case SHN_UNDEF: + str_exception(ERR_INV_FORMAT, "Invalid relocation record"); + break; + default: + if (bf.st_shndx >= symbols->file->section_cnt) str_exception(ERR_INV_FORMAT, "Invalid relocation record"); + sym_value = (symbols->file->sections + bf.st_shndx)->addr + bf.st_value; + *destination_section = symbols->file->sections + bf.st_shndx; + break; + } + } + else { + sym_value = bf.st_value; + } + } } + + /* For executable file we don't need to apply the relocation, + * all we need is destination_section */ + if (section->file->type != ET_REL) return; + func = elf_relocate_funcs; while (func->machine != section->file->machine) { if (func->func == NULL) str_exception(ERR_INV_FORMAT, "Unsupported ELF machine code"); @@ -98,7 +184,7 @@ void drl_relocate(ELF_Section * s, U8_T offset, void * buf, size_t size, ELF_Sec if (!s->relocate) return; section = s; - destination = dst; + destination_section = dst; reloc_offset = offset; data_buf = buf; data_size = size; diff --git a/services/runctrl.c b/services/runctrl.c index 814451fc..e3735ada 100644 --- a/services/runctrl.c +++ b/services/runctrl.c @@ -1039,7 +1039,7 @@ static int update_step_machine_state(Context * ctx) { if (n < 0) return -1; if (ext->step_cnt == 0) { if (n == 0) { - set_errno(ERR_INV_COMMAND, "No parent stack frame"); + set_errno(ERR_OTHER, "Cannot step out: no parent stack frame"); return -1; } if (get_frame_info(ctx, n - 1, &info) < 0) return -1; diff --git a/services/symbols_proxy.c b/services/symbols_proxy.c index 9e3331e2..98f9e967 100644 --- a/services/symbols_proxy.c +++ b/services/symbols_proxy.c @@ -136,7 +136,7 @@ typedef struct StackFrameCache { ReplyHandlerInfo * pending; ErrorReport * error; Context * ctx; - ContextAddress ip; + uint64_t ip; uint64_t address; uint64_t size; @@ -1022,7 +1022,7 @@ static void validate_frame(Channel * c, void * args, int error) { size = json_read_uint64(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (error || size == 0) { - f->address = f->ip & ~(ContextAddress)3; + f->address = f->ip & ~(uint64_t)3; f->size = 4; } else { diff --git a/services/tcf_elf.c b/services/tcf_elf.c index d4c5111f..70013b8c 100644 --- a/services/tcf_elf.c +++ b/services/tcf_elf.c @@ -916,9 +916,16 @@ ContextAddress elf_map_to_run_time_address(Context * ctx, ELF_File * file, ELF_S if (get_map(ctx, 0, ~(ContextAddress)0, &elf_map) < 0) return 0; for (i = 0; i < elf_map.region_cnt; i++) { MemoryRegion * r = elf_map.regions + i; - ino_t ino = r->ino; - if (ino == 0 && (ino = elf_ino(r->file_name)) == 0) continue; - if (file->dev != r->dev || file->ino != ino) { + int same_file = 0; + if (r->dev == 0) { + same_file = strcmp(file->name, r->file_name) == 0; + } + else { + ino_t ino = r->ino; + if (ino == 0) ino = elf_ino(r->file_name); + same_file = file->ino == ino && file->dev == r->dev; + } + if (!same_file) { /* Check if the memory map entry has a separate debug info file */ int error = 0; ELF_File * exec = NULL; diff --git a/services/tcf_elf.h b/services/tcf_elf.h index 7aef1251..521b95de 100644 --- a/services/tcf_elf.h +++ b/services/tcf_elf.h @@ -232,8 +232,8 @@ typedef struct { Elf32_Sword r_addend; } Elf32_Rela; -#define ELF32_R_SYM(i) ((i)>>8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((uint8_t)(i)) typedef struct { Elf32_Sword d_tag; @@ -301,6 +301,20 @@ typedef struct { #define ELF64_ST_TYPE(info) ((info) & 0xf) typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; +} Elf64_Rel; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +#define ELF64_R_SYM(i) ((uint32_t)((i) >> 32)) +#define ELF64_R_TYPE(i) ((uint32_t)(i)) + +typedef struct { Elf64_Sxword d_tag; union { Elf64_Xword d_val; |