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