1da0c48c4Sopenharmony_ci/* Copyright (C) 2015 Red Hat, Inc. 2da0c48c4Sopenharmony_ci This file is part of elfutils. 3da0c48c4Sopenharmony_ci 4da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 5da0c48c4Sopenharmony_ci it under the terms of the GNU General Public License as published by 6da0c48c4Sopenharmony_ci the Free Software Foundation; either version 3 of the License, or 7da0c48c4Sopenharmony_ci (at your option) any later version. 8da0c48c4Sopenharmony_ci 9da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 10da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 11da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12da0c48c4Sopenharmony_ci GNU General Public License for more details. 13da0c48c4Sopenharmony_ci 14da0c48c4Sopenharmony_ci You should have received a copy of the GNU General Public License 15da0c48c4Sopenharmony_ci along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16da0c48c4Sopenharmony_ci 17da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 18da0c48c4Sopenharmony_ci# include <config.h> 19da0c48c4Sopenharmony_ci#endif 20da0c48c4Sopenharmony_ci 21da0c48c4Sopenharmony_ci#include <system.h> 22da0c48c4Sopenharmony_ci 23da0c48c4Sopenharmony_ci#include <sys/types.h> 24da0c48c4Sopenharmony_ci#include <sys/stat.h> 25da0c48c4Sopenharmony_ci#include <fcntl.h> 26da0c48c4Sopenharmony_ci#include <inttypes.h> 27da0c48c4Sopenharmony_ci#include <libelf.h> 28da0c48c4Sopenharmony_ci#include <gelf.h> 29da0c48c4Sopenharmony_ci#include <stdbool.h> 30da0c48c4Sopenharmony_ci#include <stdio.h> 31da0c48c4Sopenharmony_ci#include <stdlib.h> 32da0c48c4Sopenharmony_ci#include <string.h> 33da0c48c4Sopenharmony_ci#include <unistd.h> 34da0c48c4Sopenharmony_ci 35da0c48c4Sopenharmony_ci 36da0c48c4Sopenharmony_ciint 37da0c48c4Sopenharmony_cimain (int argc, char *argv[]) 38da0c48c4Sopenharmony_ci{ 39da0c48c4Sopenharmony_ci int result = 0; 40da0c48c4Sopenharmony_ci int cnt; 41da0c48c4Sopenharmony_ci 42da0c48c4Sopenharmony_ci if (argc < 3 43da0c48c4Sopenharmony_ci || (strcmp (argv[1], "elf") != 0 44da0c48c4Sopenharmony_ci && strcmp (argv[1], "gnu") != 0)) 45da0c48c4Sopenharmony_ci { 46da0c48c4Sopenharmony_ci printf ("Usage: (elf|gnu) files...\n"); 47da0c48c4Sopenharmony_ci return -1; 48da0c48c4Sopenharmony_ci } 49da0c48c4Sopenharmony_ci 50da0c48c4Sopenharmony_ci int gnu; 51da0c48c4Sopenharmony_ci if (strcmp (argv[1], "gnu") == 0) 52da0c48c4Sopenharmony_ci gnu = 1; 53da0c48c4Sopenharmony_ci else 54da0c48c4Sopenharmony_ci gnu = 0; 55da0c48c4Sopenharmony_ci 56da0c48c4Sopenharmony_ci elf_version (EV_CURRENT); 57da0c48c4Sopenharmony_ci 58da0c48c4Sopenharmony_ci for (cnt = 2; cnt < argc; ++cnt) 59da0c48c4Sopenharmony_ci { 60da0c48c4Sopenharmony_ci int fd = open (argv[cnt], O_RDONLY); 61da0c48c4Sopenharmony_ci 62da0c48c4Sopenharmony_ci Elf *elf = elf_begin (fd, ELF_C_READ, NULL); 63da0c48c4Sopenharmony_ci if (elf == NULL) 64da0c48c4Sopenharmony_ci { 65da0c48c4Sopenharmony_ci printf ("%s not usable %s\n", argv[cnt], elf_errmsg (-1)); 66da0c48c4Sopenharmony_ci result = 1; 67da0c48c4Sopenharmony_ci close (fd); 68da0c48c4Sopenharmony_ci continue; 69da0c48c4Sopenharmony_ci } 70da0c48c4Sopenharmony_ci 71da0c48c4Sopenharmony_ci /* To get the section names. */ 72da0c48c4Sopenharmony_ci size_t strndx; 73da0c48c4Sopenharmony_ci elf_getshdrstrndx (elf, &strndx); 74da0c48c4Sopenharmony_ci 75da0c48c4Sopenharmony_ci Elf_Scn *scn = NULL; 76da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (elf, scn)) != NULL) 77da0c48c4Sopenharmony_ci { 78da0c48c4Sopenharmony_ci size_t idx = elf_ndxscn (scn); 79da0c48c4Sopenharmony_ci GElf_Shdr mem; 80da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (scn, &mem); 81da0c48c4Sopenharmony_ci const char *name = elf_strptr (elf, strndx, shdr->sh_name); 82da0c48c4Sopenharmony_ci if (shdr->sh_type == SHT_NOBITS 83da0c48c4Sopenharmony_ci || (shdr->sh_flags & SHF_ALLOC) != 0) 84da0c48c4Sopenharmony_ci { 85da0c48c4Sopenharmony_ci printf ("Cannot compress %zd %s\n", idx, name); 86da0c48c4Sopenharmony_ci } 87da0c48c4Sopenharmony_ci else if ((shdr->sh_flags & SHF_COMPRESSED) != 0 88da0c48c4Sopenharmony_ci || startswith (name, ".zdebug")) 89da0c48c4Sopenharmony_ci { 90da0c48c4Sopenharmony_ci printf ("Already compressed %zd %s\n", idx, name); 91da0c48c4Sopenharmony_ci } 92da0c48c4Sopenharmony_ci else 93da0c48c4Sopenharmony_ci { 94da0c48c4Sopenharmony_ci size_t orig_size = shdr->sh_size; 95da0c48c4Sopenharmony_ci printf ("Lets compress %zd %s, size: %" PRId64 "\n", 96da0c48c4Sopenharmony_ci idx, name, shdr->sh_size); 97da0c48c4Sopenharmony_ci Elf_Data *d = elf_getdata (scn, NULL); 98da0c48c4Sopenharmony_ci if (d == NULL) 99da0c48c4Sopenharmony_ci { 100da0c48c4Sopenharmony_ci printf ("Couldn't get orig data for section %zd\n", idx); 101da0c48c4Sopenharmony_ci return -1; 102da0c48c4Sopenharmony_ci } 103da0c48c4Sopenharmony_ci /* Make a copy so we can compare after 104da0c48c4Sopenharmony_ci compression/decompression. */ 105da0c48c4Sopenharmony_ci if (d->d_size != orig_size) 106da0c48c4Sopenharmony_ci { 107da0c48c4Sopenharmony_ci printf ("Unexpected data size for orig section %zd\n", idx); 108da0c48c4Sopenharmony_ci return -1; 109da0c48c4Sopenharmony_ci } 110da0c48c4Sopenharmony_ci char *orig_buf = NULL; 111da0c48c4Sopenharmony_ci if (orig_size > 0) 112da0c48c4Sopenharmony_ci { 113da0c48c4Sopenharmony_ci orig_buf = malloc (d->d_size); 114da0c48c4Sopenharmony_ci if (orig_buf == NULL) 115da0c48c4Sopenharmony_ci { 116da0c48c4Sopenharmony_ci printf ("No memory to copy section %zd data\n", idx); 117da0c48c4Sopenharmony_ci return -1; 118da0c48c4Sopenharmony_ci } 119da0c48c4Sopenharmony_ci memcpy (orig_buf, d->d_buf, orig_size); 120da0c48c4Sopenharmony_ci } 121da0c48c4Sopenharmony_ci 122da0c48c4Sopenharmony_ci bool forced = false; 123da0c48c4Sopenharmony_ci if (gnu) 124da0c48c4Sopenharmony_ci { 125da0c48c4Sopenharmony_ci int res = elf_compress_gnu (scn, 1, 0); 126da0c48c4Sopenharmony_ci if (res == 0) 127da0c48c4Sopenharmony_ci { 128da0c48c4Sopenharmony_ci forced = true; 129da0c48c4Sopenharmony_ci res = elf_compress_gnu (scn, 1, ELF_CHF_FORCE); 130da0c48c4Sopenharmony_ci } 131da0c48c4Sopenharmony_ci if (res < 0) 132da0c48c4Sopenharmony_ci { 133da0c48c4Sopenharmony_ci printf ("elf_compress_gnu%sfailed for section %zd: %s\n", 134da0c48c4Sopenharmony_ci forced ? " (forced) " : " ", 135da0c48c4Sopenharmony_ci idx, elf_errmsg (-1)); 136da0c48c4Sopenharmony_ci return -1; 137da0c48c4Sopenharmony_ci } 138da0c48c4Sopenharmony_ci } 139da0c48c4Sopenharmony_ci else 140da0c48c4Sopenharmony_ci { 141da0c48c4Sopenharmony_ci int res = elf_compress (scn, ELFCOMPRESS_ZLIB, 0); 142da0c48c4Sopenharmony_ci if (res == 0) 143da0c48c4Sopenharmony_ci { 144da0c48c4Sopenharmony_ci forced = true; 145da0c48c4Sopenharmony_ci res = elf_compress (scn, ELFCOMPRESS_ZLIB, ELF_CHF_FORCE); 146da0c48c4Sopenharmony_ci } 147da0c48c4Sopenharmony_ci if (res < 0) 148da0c48c4Sopenharmony_ci { 149da0c48c4Sopenharmony_ci printf ("elf_compress%sfailed for section %zd: %s\n", 150da0c48c4Sopenharmony_ci forced ? " (forced) " : " ", 151da0c48c4Sopenharmony_ci idx, elf_errmsg (-1)); 152da0c48c4Sopenharmony_ci return -1; 153da0c48c4Sopenharmony_ci } 154da0c48c4Sopenharmony_ci } 155da0c48c4Sopenharmony_ci GElf_Shdr newmem; 156da0c48c4Sopenharmony_ci GElf_Shdr *newshdr = gelf_getshdr (scn, &newmem); 157da0c48c4Sopenharmony_ci size_t new_size = newshdr->sh_size; 158da0c48c4Sopenharmony_ci d = elf_getdata (scn, NULL); 159da0c48c4Sopenharmony_ci // Don't check this, might depend on zlib implementation. 160da0c48c4Sopenharmony_ci // fprintf (stderr, " new_size: %zd\n", new_size); 161da0c48c4Sopenharmony_ci if (d->d_size != new_size) 162da0c48c4Sopenharmony_ci { 163da0c48c4Sopenharmony_ci printf ("Unexpected data size for compressed section %zd\n", 164da0c48c4Sopenharmony_ci idx); 165da0c48c4Sopenharmony_ci return -1; 166da0c48c4Sopenharmony_ci } 167da0c48c4Sopenharmony_ci 168da0c48c4Sopenharmony_ci if (forced && new_size < orig_size) 169da0c48c4Sopenharmony_ci { 170da0c48c4Sopenharmony_ci printf ("section %zd forced to compress, but size smaller\n", 171da0c48c4Sopenharmony_ci idx); 172da0c48c4Sopenharmony_ci return -1; 173da0c48c4Sopenharmony_ci } 174da0c48c4Sopenharmony_ci 175da0c48c4Sopenharmony_ci if (! forced && new_size >= orig_size) 176da0c48c4Sopenharmony_ci { 177da0c48c4Sopenharmony_ci printf ("section %zd compressed to bigger size\n", 178da0c48c4Sopenharmony_ci idx); 179da0c48c4Sopenharmony_ci return -1; 180da0c48c4Sopenharmony_ci } 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_ci if (new_size == orig_size 183da0c48c4Sopenharmony_ci && (orig_buf == NULL 184da0c48c4Sopenharmony_ci || memcmp (orig_buf, d->d_buf, orig_size) == 0)) 185da0c48c4Sopenharmony_ci { 186da0c48c4Sopenharmony_ci printf ("section %zd didn't compress\n", idx); 187da0c48c4Sopenharmony_ci return -1; 188da0c48c4Sopenharmony_ci } 189da0c48c4Sopenharmony_ci 190da0c48c4Sopenharmony_ci if (gnu) 191da0c48c4Sopenharmony_ci { 192da0c48c4Sopenharmony_ci if (elf_compress_gnu (scn, 0, 0) < 0) 193da0c48c4Sopenharmony_ci { 194da0c48c4Sopenharmony_ci printf ("elf_[un]compress_gnu failed for section %zd: %s\n", 195da0c48c4Sopenharmony_ci idx, elf_errmsg (-1)); 196da0c48c4Sopenharmony_ci return -1; 197da0c48c4Sopenharmony_ci } 198da0c48c4Sopenharmony_ci } 199da0c48c4Sopenharmony_ci else 200da0c48c4Sopenharmony_ci { 201da0c48c4Sopenharmony_ci if (elf_compress (scn, 0, 0) < 0) 202da0c48c4Sopenharmony_ci { 203da0c48c4Sopenharmony_ci printf ("elf_[un]compress failed for section %zd: %s\n", 204da0c48c4Sopenharmony_ci idx, elf_errmsg (-1)); 205da0c48c4Sopenharmony_ci return -1; 206da0c48c4Sopenharmony_ci } 207da0c48c4Sopenharmony_ci } 208da0c48c4Sopenharmony_ci GElf_Shdr newermem; 209da0c48c4Sopenharmony_ci GElf_Shdr *newershdr = gelf_getshdr (scn, &newermem); 210da0c48c4Sopenharmony_ci size_t newer_size = newershdr->sh_size; 211da0c48c4Sopenharmony_ci d = elf_getdata (scn, NULL); 212da0c48c4Sopenharmony_ci // fprintf (stderr, " newer_size: %zd\n", newer_size); 213da0c48c4Sopenharmony_ci if (d->d_size != newer_size) 214da0c48c4Sopenharmony_ci { 215da0c48c4Sopenharmony_ci printf ("Unexpected data size for compressed section %zd\n", 216da0c48c4Sopenharmony_ci idx); 217da0c48c4Sopenharmony_ci return -1; 218da0c48c4Sopenharmony_ci } 219da0c48c4Sopenharmony_ci if (newer_size != orig_size 220da0c48c4Sopenharmony_ci && (orig_buf == NULL 221da0c48c4Sopenharmony_ci || memcmp (orig_buf, d->d_buf, orig_size) != 0)) 222da0c48c4Sopenharmony_ci { 223da0c48c4Sopenharmony_ci printf ("section %zd didn't correctly uncompress\n", idx); 224da0c48c4Sopenharmony_ci return -1; 225da0c48c4Sopenharmony_ci } 226da0c48c4Sopenharmony_ci free (orig_buf); 227da0c48c4Sopenharmony_ci // Recompress the string table, just to make sure 228da0c48c4Sopenharmony_ci // everything keeps working. See elf_strptr above. 229da0c48c4Sopenharmony_ci if (! gnu && idx == strndx 230da0c48c4Sopenharmony_ci && elf_compress (scn, ELFCOMPRESS_ZLIB, 0) < 0) 231da0c48c4Sopenharmony_ci { 232da0c48c4Sopenharmony_ci printf ("couldn't recompress section header strings: %s\n", 233da0c48c4Sopenharmony_ci elf_errmsg (-1)); 234da0c48c4Sopenharmony_ci return -1; 235da0c48c4Sopenharmony_ci } 236da0c48c4Sopenharmony_ci } 237da0c48c4Sopenharmony_ci } 238da0c48c4Sopenharmony_ci 239da0c48c4Sopenharmony_ci elf_end (elf); 240da0c48c4Sopenharmony_ci close (fd); 241da0c48c4Sopenharmony_ci } 242da0c48c4Sopenharmony_ci 243da0c48c4Sopenharmony_ci return result; 244da0c48c4Sopenharmony_ci} 245