From e815a52ea3ece2d2546ef15888197e0c059e8ac4 Mon Sep 17 00:00:00 2001 From: Eugene Tarassov Date: Wed, 22 Aug 2018 10:19:45 -0700 Subject: TCF Agent: added support for compressed ELF sections --- agent/msvc/agent-vc2015.vcxproj | 2 + agent/msvc/agent-vc2015.vcxproj.filters | 6 + agent/tcf/framework/compression.c | 325 +++++++++++++++++++++ agent/tcf/framework/compression.h | 28 ++ agent/tcf/services/dwarfio.c | 15 +- agent/tcf/services/tcf_elf.c | 148 +++++++++- agent/tcf/services/tcf_elf.h | 8 +- server/msvc/server-vc2015.vcxproj | 2 + server/msvc/server-vc2015.vcxproj.filters | 6 + tests/test-dwarf/msvc/test-dwarf-vc2015.vcxproj | 2 + .../msvc/test-dwarf-vc2015.vcxproj.filters | 6 + 11 files changed, 527 insertions(+), 21 deletions(-) create mode 100644 agent/tcf/framework/compression.c create mode 100644 agent/tcf/framework/compression.h diff --git a/agent/msvc/agent-vc2015.vcxproj b/agent/msvc/agent-vc2015.vcxproj index 1f3db109..a03041c4 100644 --- a/agent/msvc/agent-vc2015.vcxproj +++ b/agent/msvc/agent-vc2015.vcxproj @@ -308,6 +308,7 @@ + @@ -376,6 +377,7 @@ + diff --git a/agent/msvc/agent-vc2015.vcxproj.filters b/agent/msvc/agent-vc2015.vcxproj.filters index 152d9257..3d6df3d6 100644 --- a/agent/msvc/agent-vc2015.vcxproj.filters +++ b/agent/msvc/agent-vc2015.vcxproj.filters @@ -402,6 +402,9 @@ http + + framework + @@ -861,5 +864,8 @@ framework + + framework + \ No newline at end of file diff --git a/agent/tcf/framework/compression.c b/agent/tcf/framework/compression.c new file mode 100644 index 00000000..34fa1931 --- /dev/null +++ b/agent/tcf/framework/compression.c @@ -0,0 +1,325 @@ +/******************************************************************************* +* Copyright (c) 2018 Xilinx, Inc. and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* and Eclipse Distribution License v1.0 which accompany this distribution. +* The Eclipse Public License is available at +* http://www.eclipse.org/legal/epl-v10.html +* and the Eclipse Distribution License is available at +* http://www.eclipse.org/org/documents/edl-v10.php. +* You may elect to redistribute this code under either of these licenses. +* +* Contributors: +* Xilinx - initial API and implementation +*******************************************************************************/ + +/* + * Implements RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + * + * RFC 1951 defines a lossless compressed data format that + * compresses data using a combination of the LZ77 algorithm and Huffman coding. + * + * Only decompressor is implemented. + */ + +#include + +#include +#include +#include +#include + +#define FAST_LOOKUP_BITS 8 +#define MAX_SYMBOLS_CNT 288 + +typedef struct HuffmanSymbol { + uint16_t code; + uint8_t size; + uint8_t tree; +} HuffmanSymbol; + +typedef struct HuffmanTable { + unsigned syms_cnt; + uint8_t code_size[MAX_SYMBOLS_CNT]; + HuffmanSymbol lookup[1 << FAST_LOOKUP_BITS]; + HuffmanSymbol tree[MAX_SYMBOLS_CNT * 2]; +} HuffmanTable; + +static HuffmanTable tables[3]; + +static uint8_t * inp_buf = NULL; +static size_t inp_size = 0; +static unsigned inp_pos = 0; +static uint32_t inp_bit_buf = 0; +static unsigned inp_bit_cnt = 0; +static uint8_t * out_buf = NULL; +static size_t out_size = 0; +static unsigned out_pos = 0; + +static unsigned get_bits(unsigned bit_cnt) { + unsigned v = 0; + if (bit_cnt > 0) { + assert(bit_cnt <= 32); + while (inp_bit_cnt < bit_cnt) { + if (inp_pos >= inp_size) exception(ERR_BUFFER_OVERFLOW); + inp_bit_buf |= (uint32_t)inp_buf[inp_pos++] << inp_bit_cnt; + inp_bit_cnt += 8; + } + v = inp_bit_buf & ((1u << bit_cnt) - 1); + inp_bit_buf >>= bit_cnt; + inp_bit_cnt -= bit_cnt; + } + return v; +} + +static unsigned decode_huffman_symbol(HuffmanTable * t) { + HuffmanSymbol v; + + while (inp_bit_cnt < 15) { + if (inp_pos >= inp_size) exception(ERR_BUFFER_OVERFLOW); + inp_bit_buf |= (uint32_t)inp_buf[inp_pos++] << inp_bit_cnt; + inp_bit_cnt += 8; + } + + v = t->lookup[inp_bit_buf & ((1 << FAST_LOOKUP_BITS) - 1)]; + if (v.tree) { + unsigned b = FAST_LOOKUP_BITS; + do { + assert(b <= 14); + assert(v.code <= MAX_SYMBOLS_CNT * 2 - 2); + v = t->tree[v.code + ((inp_bit_buf >> b++) & 1)]; + } + while (v.tree); + assert(v.size == b); + } + assert(v.size <= 15); + if (v.size == 0) exception(ERR_OTHER); + inp_bit_buf >>= v.size; + inp_bit_cnt -= v.size; + return v.code; +} + +static void decode_tables(unsigned type) { + memset(tables, 0, sizeof(tables)); + if (type == 1) { + unsigned t; + for (t = 0; t < 2; t++) { + unsigned i = 0; + uint8_t * p = tables[t].code_size; + switch (t) { + case 0: + for (; i <= 143; i++) *p++ = 8; + for (; i <= 255; i++) *p++ = 9; + for (; i <= 279; i++) *p++ = 7; + for (; i <= 287; i++) *p++ = 8; + tables[t].syms_cnt = MAX_SYMBOLS_CNT; + break; + case 1: + for (; i <= 31; i++) *p++ = 5; + tables[t].syms_cnt = 32; + break; + } + } + } + else { + unsigned i; + static const uint8_t zigzag[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + tables[0].syms_cnt = get_bits(5) + 257; + tables[1].syms_cnt = get_bits(5) + 1; + tables[2].syms_cnt = get_bits(4) + 4; + for (i = 0; i < tables[2].syms_cnt; i++) { + tables[2].code_size[zigzag[i]] = (uint8_t)get_bits(3); + } + tables[2].syms_cnt = 19; + } + for (;;) { + unsigned i; + unsigned sym; + unsigned syms_used = 0; + unsigned syms_total = 0; + unsigned syms_next[17]; + unsigned syms_per_size[16]; + HuffmanSymbol hs, hs_next; + + memset(syms_next, 0, sizeof(syms_next)); + memset(syms_per_size, 0, sizeof(syms_per_size)); + for (i = 0; i < tables[type].syms_cnt; i++) syms_per_size[tables[type].code_size[i]]++; + for (i = 1; i <= 15; i++) { + syms_used += syms_per_size[i]; + syms_total = (syms_total + syms_per_size[i]) << 1; + syms_next[i + 1] = syms_total; + } + if (syms_total != 0x10000 && syms_used > 1) exception(ERR_OTHER); + + hs_next.tree = 1; + hs_next.code = 0; + hs_next.size = 0; + for (sym = 0; sym < tables[type].syms_cnt; sym++) { + unsigned code_size = tables[type].code_size[sym]; + unsigned rev_code = 0; + unsigned cur_code = 0; + if (code_size == 0) continue; + assert(code_size <= 15); + cur_code = syms_next[code_size]++; + for (i = 0; i < code_size; i++) { + rev_code <<= 1; + rev_code = rev_code | (cur_code & 1); + cur_code >>= 1; + } + if (code_size <= FAST_LOOKUP_BITS) { + hs.tree = 0; + hs.code = (uint16_t)sym; + hs.size = (uint8_t)code_size; + while (rev_code < (1 << FAST_LOOKUP_BITS)) { + tables[type].lookup[rev_code] = hs; + rev_code += 1 << code_size; + } + continue; + } + hs = tables[type].lookup[rev_code & ((1 << FAST_LOOKUP_BITS) - 1)]; + assert(hs.size == 0); + if (hs.tree == 0) { + hs = tables[type].lookup[rev_code & ((1 << FAST_LOOKUP_BITS) - 1)] = hs_next; + hs_next.code += 2; + } + rev_code >>= FAST_LOOKUP_BITS; + for (i = code_size; i > FAST_LOOKUP_BITS + 1; i--) { + hs.code += rev_code & 1; + if (tables[type].tree[hs.code].tree) { + hs = tables[type].tree[hs.code]; + } + else { + hs = tables[type].tree[hs.code] = hs_next; + hs_next.code += 2; + } + rev_code >>= 1; + } + assert(hs_next.code <= MAX_SYMBOLS_CNT * 2); + hs.code += rev_code & 1; + tables[type].tree[hs.code].code = (uint16_t)sym; + tables[type].tree[hs.code].size = (uint8_t)code_size; + } + + if (type == 2) { + uint8_t len_codes[MAX_SYMBOLS_CNT + 32 + 137]; + i = 0; + while (i < tables[0].syms_cnt + tables[1].syms_cnt) { + unsigned s = 0; + unsigned d = decode_huffman_symbol(tables + 2); + if (d < 16) { + len_codes[i++] = (uint8_t)d; + continue; + } + if (d == 16 && i == 0) exception(ERR_OTHER); + switch (d - 16) { + case 0: s = get_bits(2) + 3; break; + case 1: s = get_bits(3) + 3; break; + case 2: s = get_bits(7) + 11; break; + } + if (s == 0) exception(ERR_OTHER); + memset(len_codes + i, d == 16 ? len_codes[i - 1] : 0, s); + i += s; + } + if (tables[0].syms_cnt + tables[1].syms_cnt != i) exception(ERR_OTHER); + memcpy(tables[0].code_size, len_codes, tables[0].syms_cnt); + memcpy(tables[1].code_size, len_codes + tables[0].syms_cnt, tables[1].syms_cnt); + } + if (type == 0) break; + type--; + } +} + +static void decode_data_block() { + static const unsigned length_base[31] = { + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, + 131, 163, 195, 227, 258, 0, 0 + }; + static const unsigned length_extra[31] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, + 5, 5, 5, 5, 0, 0, 0 + }; + static const unsigned dist_base[32] = { + 1, 2, 3, 4, 5, 7, 9, 13, + 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, + 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 + }; + static const unsigned dist_extra[32] = { + 0, 0, 0, 0, 1, 1, 2, 2, + 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, + 11, 11, 12, 12, 13, 13, 0, 0 + }; + for (;;) { + unsigned sym = decode_huffman_symbol(tables); + if (sym < 256) { + if (out_pos >= out_size) exception(ERR_OTHER); + out_buf[out_pos++] = (uint8_t)sym; + } + else if (sym == 256) { + return; + } + else { + unsigned len = length_base[sym - 257] + get_bits(length_extra[sym - 257]); + unsigned sym_ofs = decode_huffman_symbol(tables + 1); + unsigned ofs = dist_base[sym_ofs] + get_bits(dist_extra[sym_ofs]); + + if (ofs > out_pos) exception(ERR_OTHER); + if (out_pos + len > out_size) exception(ERR_OTHER); + + while (len > 0) { + out_buf[out_pos] = out_buf[out_pos - ofs]; + out_pos++; + len--; + } + } + } +} + +unsigned decompress(void * src_buf, size_t src_size, void * dst_buf, size_t dst_size) { + inp_buf = (uint8_t *)src_buf; + inp_size = src_size; + inp_pos = 0; + inp_bit_buf = 0; + inp_bit_cnt = 0; + out_buf = (uint8_t *)dst_buf; + out_size = dst_size; + out_pos = 0; + for (;;) { + unsigned final = get_bits(1); + unsigned type = get_bits(2); + if (type == 0) { + unsigned len = 0, nlen = 0; + inp_pos -= inp_bit_cnt >> 3; + inp_bit_cnt = 0; + if (inp_pos + 4 > inp_size) exception(ERR_OTHER); + len |= inp_buf[inp_pos++]; + len |= (unsigned)inp_buf[inp_pos++] << 8; + nlen |= inp_buf[inp_pos++]; + nlen |= (unsigned)inp_buf[inp_pos++] << 8; + if ((len ^ nlen) != 0xffff) exception(ERR_OTHER); + if (inp_pos + len > inp_size) exception(ERR_OTHER); + if (out_pos + len > out_size) exception(ERR_OTHER); + memcpy(out_buf + out_pos, inp_buf + inp_pos, len); + inp_pos += len; + out_pos += len; + } + else if (type == 3) { + exception(ERR_OTHER); + } + else { + decode_tables(type); + decode_data_block(); + } + if (final) break; + } + inp_pos -= inp_bit_cnt >> 3; + inp_bit_cnt = 0; + return inp_pos; +} diff --git a/agent/tcf/framework/compression.h b/agent/tcf/framework/compression.h new file mode 100644 index 00000000..ffc1abf4 --- /dev/null +++ b/agent/tcf/framework/compression.h @@ -0,0 +1,28 @@ +/******************************************************************************* +* Copyright (c) 2018 Xilinx, Inc. and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* and Eclipse Distribution License v1.0 which accompany this distribution. +* The Eclipse Public License is available at +* http://www.eclipse.org/legal/epl-v10.html +* and the Eclipse Distribution License is available at +* http://www.eclipse.org/org/documents/edl-v10.php. +* You may elect to redistribute this code under either of these licenses. +* +* Contributors: +* Xilinx - initial API and implementation +*******************************************************************************/ + +/* + * Implements RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + * Only decompressor is implemented. + */ + +#ifndef D_compression +#define D_compression + +#include + +extern unsigned decompress(void * src_buf, size_t src_size, void * dst_buf, size_t dst_size); + +#endif /* D_compression */ diff --git a/agent/tcf/services/dwarfio.c b/agent/tcf/services/dwarfio.c index 461a929f..96011acf 100644 --- a/agent/tcf/services/dwarfio.c +++ b/agent/tcf/services/dwarfio.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2017 Wind River Systems, Inc. and others. + * Copyright (c) 2006-2018 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. @@ -339,11 +339,12 @@ static U1_T * dio_LoadStringTable(ELF_File * File, U8_T * StringTableAddr, U4_T str_exception(ERR_INV_DWARF, "Section .debug_str not found"); } - Cache->mStringTableAddr = Section->addr; - Cache->mStringTableSize = (size_t)Section->size; if (elf_load(Section) < 0) { str_exception(errno, "Cannot read .debug_str section"); } + + Cache->mStringTableAddr = Section->addr; + Cache->mStringTableSize = (size_t)Section->size; Cache->mStringTable = (U1_T *)Section->data; } @@ -660,7 +661,6 @@ void dio_ReadUnit(DIO_UnitDescriptor * Unit, DIO_EntryCallBack CallBack) { #define dio_AbbrevTableHash(Offset) (((unsigned)(Offset)) / 16 % ABBREV_TABLE_SIZE) void dio_LoadAbbrevTable(ELF_File * File) { - U4_T ID; U8_T TableOffset = 0; ELF_Section * Section = NULL; static U2_T * AttrBuf = NULL; @@ -669,16 +669,17 @@ void dio_LoadAbbrevTable(ELF_File * File) { static U4_T AbbrevBufSize = 0; U4_T AbbrevBufPos = 0; DIO_Cache * Cache = dio_GetCache(File); + unsigned i; if (Cache->mAbbrevTable != NULL) return; Cache->mAbbrevTable = (DIO_AbbrevSet **)loc_alloc_zero(sizeof(DIO_AbbrevSet *) * ABBREV_TABLE_SIZE); - for (ID = 1; ID < File->section_cnt; ID++) { - if (strcmp(File->sections[ID].name, ".debug_abbrev") == 0) { + for (i = 1; i < File->section_cnt; i++) { + if (strcmp(File->sections[i].name, ".debug_abbrev") == 0) { if (Section != NULL) { str_exception(ERR_INV_DWARF, "More then one .debug_abbrev section in a file"); } - Section = File->sections + ID; + Section = File->sections + i; } } if (Section == NULL) return; diff --git a/agent/tcf/services/tcf_elf.c b/agent/tcf/services/tcf_elf.c index 93690604..c1ffeb0e 100644 --- a/agent/tcf/services/tcf_elf.c +++ b/agent/tcf/services/tcf_elf.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -58,10 +59,18 @@ #define MAX_FILE_AGE 60 #define MAX_FILE_CNT 100 +#ifndef SHF_COMPRESSED +#define SHF_COMPRESSED 0x00000800 +#endif +#ifndef ELFCOMPRESS_ZLIB +#define ELFCOMPRESS_ZLIB 1 +#endif #ifndef ARCH_SHF_SMALL #define ARCH_SHF_SMALL 0 #endif +#define SHDR_BUF_SIZE 64 + typedef struct FileINode { struct FileINode * next; char * name; @@ -704,18 +713,28 @@ static ELF_File * create_elf_cache(const char * file_name) { if (error == 0 && hdr.e_shoff == 0) { error = set_errno(ERR_INV_FORMAT, "Invalid section header table's file offset"); } - if (error == 0 && lseek(file->fd, hdr.e_shoff, SEEK_SET) == (off_t)-1) error = errno; if (error == 0) { unsigned cnt = 0; + uint8_t * shdr_buf = (uint8_t *)tmp_alloc(hdr.e_shentsize * SHDR_BUF_SIZE); file->sections = (ELF_Section *)loc_alloc_zero(sizeof(ELF_Section) * hdr.e_shnum); file->section_cnt = hdr.e_shnum; while (error == 0 && cnt < hdr.e_shnum) { - Elf32_Shdr shdr; - memset(&shdr, 0, sizeof(shdr)); - if (error == 0 && sizeof(shdr) < hdr.e_shentsize) error = ERR_INV_FORMAT; - if (error == 0 && read_fully(file->fd, (char *)&shdr, hdr.e_shentsize) < 0) error = errno; + if (cnt % SHDR_BUF_SIZE == 0) { + unsigned n = hdr.e_shnum - cnt; + if (n > SHDR_BUF_SIZE) n = SHDR_BUF_SIZE; + if (error == 0 && lseek(file->fd, hdr.e_shoff + cnt * hdr.e_shentsize, SEEK_SET) == (off_t)-1) error = errno; + if (error == 0 && read_fully(file->fd, shdr_buf, hdr.e_shentsize * n) < 0) error = errno; + } if (error == 0) { + Elf32_Shdr shdr; ELF_Section * sec = file->sections + cnt; + if (hdr.e_shentsize < sizeof(shdr)) { + memcpy(&shdr, shdr_buf + cnt % SHDR_BUF_SIZE * hdr.e_shentsize, hdr.e_shentsize); + memset((uint8_t *)&shdr + hdr.e_shentsize, 0, sizeof(shdr) - hdr.e_shentsize); + } + else { + memcpy(&shdr, shdr_buf + cnt % SHDR_BUF_SIZE * hdr.e_shentsize, sizeof(shdr)); + } if (file->byte_swap) { SWAP(shdr.sh_name); SWAP(shdr.sh_type); @@ -740,6 +759,33 @@ static ELF_File * create_elf_cache(const char * file_name) { sec->link = shdr.sh_link; sec->info = shdr.sh_info; sec->entsize = shdr.sh_entsize; + if (sec->flags & SHF_COMPRESSED) { + struct { + uint32_t type; + uint32_t size; + uint32_t alignment; + } buf; + if (sec->size < sizeof(buf)) { + error = set_errno(ERR_INV_FORMAT, "Invalid compressed section header"); + break; + } + sec->compressed_size = sec->size - sizeof(buf); + sec->compressed_offset = sec->offset + sizeof(buf); + sec->size = 0; + if (lseek(file->fd, sec->offset, SEEK_SET) == (off_t)-1 || + read_fully(file->fd, &buf, sizeof(buf)) < 0) { + error = set_errno(errno, "Cannot read symbol file"); + break; + } + if (file->byte_swap) { + SWAP(buf.type); + SWAP(buf.size); + SWAP(buf.alignment); + } + sec->compressed_type = buf.type; + sec->size = buf.size; + sec->alignment = buf.alignment; + } if (sec->type == SHT_SYMTAB || sec->type == SHT_DYNSYM) { sec->sym_count = (unsigned)(sec->size / sizeof(Elf32_Sym)); } @@ -820,18 +866,28 @@ static ELF_File * create_elf_cache(const char * file_name) { if (error == 0 && hdr.e_shoff == 0) { error = set_errno(ERR_INV_FORMAT, "Invalid section header table's file offset"); } - if (error == 0 && lseek(file->fd, hdr.e_shoff, SEEK_SET) == (off_t)-1) error = errno; if (error == 0) { unsigned cnt = 0; + uint8_t * shdr_buf = (uint8_t *)tmp_alloc(hdr.e_shentsize * SHDR_BUF_SIZE); file->sections = (ELF_Section *)loc_alloc_zero(sizeof(ELF_Section) * hdr.e_shnum); file->section_cnt = hdr.e_shnum; while (error == 0 && cnt < hdr.e_shnum) { - Elf64_Shdr shdr; - memset(&shdr, 0, sizeof(shdr)); - if (error == 0 && sizeof(shdr) < hdr.e_shentsize) error = ERR_INV_FORMAT; - if (error == 0 && read_fully(file->fd, (char *)&shdr, hdr.e_shentsize) < 0) error = errno; + if (cnt % SHDR_BUF_SIZE == 0) { + unsigned n = hdr.e_shnum - cnt; + if (n > SHDR_BUF_SIZE) n = SHDR_BUF_SIZE; + if (error == 0 && lseek(file->fd, hdr.e_shoff + cnt * hdr.e_shentsize, SEEK_SET) == (off_t)-1) error = errno; + if (error == 0 && read_fully(file->fd, shdr_buf, hdr.e_shentsize * n) < 0) error = errno; + } if (error == 0) { + Elf64_Shdr shdr; ELF_Section * sec = file->sections + cnt; + if (hdr.e_shentsize < sizeof(shdr)) { + memcpy(&shdr, shdr_buf + cnt % SHDR_BUF_SIZE * hdr.e_shentsize, hdr.e_shentsize); + memset((uint8_t *)&shdr + hdr.e_shentsize, 0, sizeof(shdr) - hdr.e_shentsize); + } + else { + memcpy(&shdr, shdr_buf + cnt % SHDR_BUF_SIZE * hdr.e_shentsize, sizeof(shdr)); + } if (file->byte_swap) { SWAP(shdr.sh_name); SWAP(shdr.sh_type); @@ -856,6 +912,34 @@ static ELF_File * create_elf_cache(const char * file_name) { sec->link = shdr.sh_link; sec->info = shdr.sh_info; sec->entsize = (U4_T)shdr.sh_entsize; + if (sec->flags & SHF_COMPRESSED) { + struct { + uint32_t type; + uint32_t reserved; + uint64_t size; + uint64_t alignment; + } buf; + if (sec->size < sizeof(buf)) { + error = set_errno(ERR_INV_FORMAT, "Invalid compressed section header"); + break; + } + sec->compressed_size = sec->size - sizeof(buf); + sec->compressed_offset = sec->offset + sizeof(buf); + sec->size = 0; + if (lseek(file->fd, sec->offset, SEEK_SET) == (off_t)-1 || + read_fully(file->fd, &buf, sizeof(buf)) < 0) { + error = set_errno(errno, "Cannot read symbol file"); + break; + } + if (file->byte_swap) { + SWAP(buf.type); + SWAP(buf.size); + SWAP(buf.alignment); + } + sec->compressed_type = buf.type; + sec->size = buf.size; + sec->alignment = (U4_T)buf.alignment; + } if (sec->type == SHT_SYMTAB || sec->type == SHT_DYNSYM) { sec->sym_count = (unsigned)(sec->size / sizeof(Elf64_Sym)); } @@ -993,7 +1077,7 @@ int elf_load(ELF_Section * s) { #if USE_MMAP #if defined(_WIN32) || defined(__CYGWIN__) - if (s->size >= 0x100000) { + if (s->size >= 0x100000 && (s->flags & SHF_COMPRESSED) == 0) { ELF_File * file = s->file; if (file->mmap_handle == NULL) { file->mmap_handle = CreateFileMapping( @@ -1023,7 +1107,7 @@ int elf_load(ELF_Section * s) { } } #else - if (s->size >= 0x100000) { + if (s->size >= 0x100000 && (s->flags & SHF_COMPRESSED) == 0) { long page = sysconf(_SC_PAGE_SIZE); off_t offs = (off_t)s->offset; offs -= offs % page; @@ -1048,6 +1132,46 @@ int elf_load(ELF_Section * s) { set_error_report_errno(file->error); return -1; } + if (s->flags & SHF_COMPRESSED) { + if (s->compressed_type == ELFCOMPRESS_ZLIB && s->compressed_size > 6) { + uint8_t * buf = (uint8_t *)loc_alloc((size_t)s->compressed_size); + if (lseek(file->fd, s->compressed_offset, SEEK_SET) == (off_t)-1 || + read_fully(file->fd, buf, (size_t)s->compressed_size) < 0) { + int error = errno; + loc_free(buf); + set_errno(error, "Cannot read symbol file"); + return -1; + } + else { + unsigned pos = 0; + unsigned cmf = buf[pos++]; + unsigned flg = buf[pos++]; + if ((cmf & 0xf) != 0x08) { + loc_free(buf); + set_errno(ERR_INV_DWARF, "Unsupported compression type"); + return -1; + } + if ((cmf * 256 + flg) % 31 == 0 && (flg & 0x20) == 0) { + Trap trap; + s->data = loc_alloc_zero((size_t)s->size); + if (set_trap(&trap)) { + pos += decompress(buf + pos, (size_t)(s->compressed_size - pos), s->data, (size_t)s->size); + if (pos + 4 <= s->compressed_size) { + /* TODO: checksum verification */ + clear_trap(&trap); + loc_free(buf); + return 0; + } + } + loc_free(s->data); + s->data = NULL; + } + } + loc_free(buf); + } + set_errno(ERR_INV_DWARF, "Corrupted compressed section"); + return -1; + } s->data = loc_alloc((size_t)s->size); if (lseek(file->fd, s->offset, SEEK_SET) == (off_t)-1 || read_fully(file->fd, s->data, (size_t)s->size) < 0) { diff --git a/agent/tcf/services/tcf_elf.h b/agent/tcf/services/tcf_elf.h index 25fa3374..62876f46 100644 --- a/agent/tcf/services/tcf_elf.h +++ b/agent/tcf/services/tcf_elf.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2015 Wind River Systems, Inc. and others. + * Copyright (c) 2007-2018 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. @@ -126,7 +126,6 @@ #define STT_HIPROC 15 #define STT_ARM_TFUNC STT_LOPROC - #define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 @@ -506,6 +505,11 @@ struct ELF_Section { U4_T info; U4_T entsize; + /* Compression info */ + U4_T compressed_type; + U8_T compressed_size; + U8_T compressed_offset; + void * mmap_addr; size_t mmap_size; diff --git a/server/msvc/server-vc2015.vcxproj b/server/msvc/server-vc2015.vcxproj index 559aa8cf..2ea0fc75 100644 --- a/server/msvc/server-vc2015.vcxproj +++ b/server/msvc/server-vc2015.vcxproj @@ -187,6 +187,7 @@ + @@ -252,6 +253,7 @@ + diff --git a/server/msvc/server-vc2015.vcxproj.filters b/server/msvc/server-vc2015.vcxproj.filters index 14dc345f..6b051f93 100644 --- a/server/msvc/server-vc2015.vcxproj.filters +++ b/server/msvc/server-vc2015.vcxproj.filters @@ -204,6 +204,9 @@ framework + + framework + @@ -438,5 +441,8 @@ framework + + framework + \ No newline at end of file diff --git a/tests/test-dwarf/msvc/test-dwarf-vc2015.vcxproj b/tests/test-dwarf/msvc/test-dwarf-vc2015.vcxproj index 319fef0f..5597f5fe 100644 --- a/tests/test-dwarf/msvc/test-dwarf-vc2015.vcxproj +++ b/tests/test-dwarf/msvc/test-dwarf-vc2015.vcxproj @@ -173,6 +173,7 @@ + @@ -248,6 +249,7 @@ + diff --git a/tests/test-dwarf/msvc/test-dwarf-vc2015.vcxproj.filters b/tests/test-dwarf/msvc/test-dwarf-vc2015.vcxproj.filters index aebaebda..e58d7aa9 100644 --- a/tests/test-dwarf/msvc/test-dwarf-vc2015.vcxproj.filters +++ b/tests/test-dwarf/msvc/test-dwarf-vc2015.vcxproj.filters @@ -237,6 +237,9 @@ framework + + framework + @@ -459,5 +462,8 @@ framework + + framework + \ No newline at end of file -- cgit v1.2.3