aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/recordmcount.h
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-10-13 19:06:14 -0400
committerSteven Rostedt <rostedt@goodmis.org>2010-10-14 16:54:00 -0400
commitc28d5077f8d79bfce1e3f88db2e261cf2b6473dc (patch)
treec291f156e75beb02dfa5615a7040a549912dd8ba /scripts/recordmcount.h
parent72441cb1fd77d092f09ddfac748955703884c9a7 (diff)
ftrace: Remove duplicate code for 64 and 32 bit in recordmcount.c
The elf reader for recordmcount.c had duplicate functions for both 32 bit and 64 bit elf handling. This was due to the need of using the 32 and 64 bit elf structures. This patch consolidates the two by using macros to define the 32 and 64 bit names in a recordmcount.h file, and then by just defining a RECORD_MCOUNT_64 macro and including recordmcount.h twice we create the funtions for both the 32 bit version as well as the 64 bit version using one code source. Cc: John Reiser <jreiser@bitwagon.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'scripts/recordmcount.h')
-rw-r--r--scripts/recordmcount.h366
1 files changed, 366 insertions, 0 deletions
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
new file mode 100644
index 00000000000..7f39d0943d2
--- /dev/null
+++ b/scripts/recordmcount.h
@@ -0,0 +1,366 @@
1/*
2 * recordmcount.h
3 *
4 * This code was taken out of recordmcount.c written by
5 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
6 *
7 * The original code had the same algorithms for both 32bit
8 * and 64bit ELF files, but the code was duplicated to support
9 * the difference in structures that were used. This
10 * file creates a macro of everything that is different between
11 * the 64 and 32 bit code, such that by including this header
12 * twice we can create both sets of functions by including this
13 * header once with RECORD_MCOUNT_64 undefined, and again with
14 * it defined.
15 *
16 * This conversion to macros was done by:
17 * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
18 *
19 * Licensed under the GNU General Public License, version 2 (GPLv2).
20 */
21#undef append_func
22#undef sift_rel_mcount
23#undef find_secsym_ndx
24#undef __has_rel_mcount
25#undef has_rel_mcount
26#undef tot_relsize
27#undef do_func
28#undef Elf_Ehdr
29#undef Elf_Shdr
30#undef Elf_Rel
31#undef Elf_Rela
32#undef Elf_Sym
33#undef ELF_R_SYM
34#undef ELF_R_INFO
35#undef ELF_ST_BIND
36#undef uint_t
37#undef _w
38#undef _align
39#undef _size
40
41#ifdef RECORD_MCOUNT_64
42# define append_func append64
43# define sift_rel_mcount sift64_rel_mcount
44# define find_secsym_ndx find64_secsym_ndx
45# define __has_rel_mcount __has64_rel_mcount
46# define has_rel_mcount has64_rel_mcount
47# define tot_relsize tot64_relsize
48# define do_func do64
49# define Elf_Ehdr Elf64_Ehdr
50# define Elf_Shdr Elf64_Shdr
51# define Elf_Rel Elf64_Rel
52# define Elf_Rela Elf64_Rela
53# define Elf_Sym Elf64_Sym
54# define ELF_R_SYM ELF64_R_SYM
55# define ELF_R_INFO ELF64_R_INFO
56# define ELF_ST_BIND ELF64_ST_BIND
57# define uint_t uint64_t
58# define _w w8
59# define _align 7u
60# define _size 8
61#else
62# define append_func append32
63# define sift_rel_mcount sift32_rel_mcount
64# define find_secsym_ndx find32_secsym_ndx
65# define __has_rel_mcount __has32_rel_mcount
66# define has_rel_mcount has32_rel_mcount
67# define tot_relsize tot32_relsize
68# define do_func do32
69# define Elf_Ehdr Elf32_Ehdr
70# define Elf_Shdr Elf32_Shdr
71# define Elf_Rel Elf32_Rel
72# define Elf_Rela Elf32_Rela
73# define Elf_Sym Elf32_Sym
74# define ELF_R_SYM ELF32_R_SYM
75# define ELF_R_INFO ELF32_R_INFO
76# define ELF_ST_BIND ELF32_ST_BIND
77# define uint_t uint32_t
78# define _w w
79# define _align 3u
80# define _size 4
81#endif
82
83/* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
84static void append_func(Elf_Ehdr *const ehdr,
85 Elf_Shdr *const shstr,
86 uint_t const *const mloc0,
87 uint_t const *const mlocp,
88 Elf_Rel const *const mrel0,
89 Elf_Rel const *const mrelp,
90 unsigned int const rel_entsize,
91 unsigned int const symsec_sh_link)
92{
93 /* Begin constructing output file */
94 Elf_Shdr mcsec;
95 char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
96 ? ".rela__mcount_loc"
97 : ".rel__mcount_loc";
98 unsigned const old_shnum = w2(ehdr->e_shnum);
99 uint_t const old_shoff = _w(ehdr->e_shoff);
100 uint_t const old_shstr_sh_size = _w(shstr->sh_size);
101 uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
102 uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
103 uint_t new_e_shoff;
104
105 shstr->sh_size = _w(t);
106 shstr->sh_offset = _w(sb.st_size);
107 t += sb.st_size;
108 t += (_align & -t); /* word-byte align */
109 new_e_shoff = t;
110
111 /* body for new shstrtab */
112 ulseek(fd_map, sb.st_size, SEEK_SET);
113 uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size);
114 uwrite(fd_map, mc_name, 1 + strlen(mc_name));
115
116 /* old(modified) Elf_Shdr table, word-byte aligned */
117 ulseek(fd_map, t, SEEK_SET);
118 t += sizeof(Elf_Shdr) * old_shnum;
119 uwrite(fd_map, old_shoff + (void *)ehdr,
120 sizeof(Elf_Shdr) * old_shnum);
121
122 /* new sections __mcount_loc and .rel__mcount_loc */
123 t += 2*sizeof(mcsec);
124 mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel")
125 + old_shstr_sh_size);
126 mcsec.sh_type = w(SHT_PROGBITS);
127 mcsec.sh_flags = _w(SHF_ALLOC);
128 mcsec.sh_addr = 0;
129 mcsec.sh_offset = _w(t);
130 mcsec.sh_size = _w((void *)mlocp - (void *)mloc0);
131 mcsec.sh_link = 0;
132 mcsec.sh_info = 0;
133 mcsec.sh_addralign = _w(_size);
134 mcsec.sh_entsize = _w(_size);
135 uwrite(fd_map, &mcsec, sizeof(mcsec));
136
137 mcsec.sh_name = w(old_shstr_sh_size);
138 mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
139 ? w(SHT_RELA)
140 : w(SHT_REL);
141 mcsec.sh_flags = 0;
142 mcsec.sh_addr = 0;
143 mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t);
144 mcsec.sh_size = _w((void *)mrelp - (void *)mrel0);
145 mcsec.sh_link = w(symsec_sh_link);
146 mcsec.sh_info = w(old_shnum);
147 mcsec.sh_addralign = _w(_size);
148 mcsec.sh_entsize = _w(rel_entsize);
149 uwrite(fd_map, &mcsec, sizeof(mcsec));
150
151 uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0);
152 uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0);
153
154 ehdr->e_shoff = _w(new_e_shoff);
155 ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */
156 ulseek(fd_map, 0, SEEK_SET);
157 uwrite(fd_map, ehdr, sizeof(*ehdr));
158}
159
160
161/*
162 * Look at the relocations in order to find the calls to mcount.
163 * Accumulate the section offsets that are found, and their relocation info,
164 * onto the end of the existing arrays.
165 */
166static uint_t *sift_rel_mcount(uint_t *mlocp,
167 unsigned const offbase,
168 Elf_Rel **const mrelpp,
169 Elf_Shdr const *const relhdr,
170 Elf_Ehdr const *const ehdr,
171 unsigned const recsym,
172 uint_t const recval,
173 unsigned const reltype)
174{
175 uint_t *const mloc0 = mlocp;
176 Elf_Rel *mrelp = *mrelpp;
177 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
178 + (void *)ehdr);
179 unsigned const symsec_sh_link = w(relhdr->sh_link);
180 Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
181 Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
182 + (void *)ehdr);
183
184 Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
185 char const *const str0 = (char const *)(_w(strsec->sh_offset)
186 + (void *)ehdr);
187
188 Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
189 + (void *)ehdr);
190 unsigned rel_entsize = _w(relhdr->sh_entsize);
191 unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
192 Elf_Rel const *relp = rel0;
193
194 unsigned mcountsym = 0;
195 unsigned t;
196
197 for (t = nrel; t; --t) {
198 if (!mcountsym) {
199 Elf_Sym const *const symp =
200 &sym0[ELF_R_SYM(_w(relp->r_info))];
201 char const *symname = &str0[w(symp->st_name)];
202
203 if ('.' == symname[0])
204 ++symname; /* ppc64 hack */
205 if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"),
206 symname))
207 mcountsym = ELF_R_SYM(_w(relp->r_info));
208 }
209
210 if (mcountsym == ELF_R_SYM(_w(relp->r_info))) {
211 uint_t const addend = _w(_w(relp->r_offset) - recval);
212
213 mrelp->r_offset = _w(offbase
214 + ((void *)mlocp - (void *)mloc0));
215 mrelp->r_info = _w(ELF_R_INFO(recsym, reltype));
216 if (sizeof(Elf_Rela) == rel_entsize) {
217 ((Elf_Rela *)mrelp)->r_addend = addend;
218 *mlocp++ = 0;
219 } else
220 *mlocp++ = addend;
221
222 mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
223 }
224 relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
225 }
226 *mrelpp = mrelp;
227 return mlocp;
228}
229
230
231/*
232 * Find a symbol in the given section, to be used as the base for relocating
233 * the table of offsets of calls to mcount. A local or global symbol suffices,
234 * but avoid a Weak symbol because it may be overridden; the change in value
235 * would invalidate the relocations of the offsets of the calls to mcount.
236 * Often the found symbol will be the unnamed local symbol generated by
237 * GNU 'as' for the start of each section. For example:
238 * Num: Value Size Type Bind Vis Ndx Name
239 * 2: 00000000 0 SECTION LOCAL DEFAULT 1
240 */
241static unsigned find_secsym_ndx(unsigned const txtndx,
242 char const *const txtname,
243 uint_t *const recvalp,
244 Elf_Shdr const *const symhdr,
245 Elf_Ehdr const *const ehdr)
246{
247 Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
248 + (void *)ehdr);
249 unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize);
250 Elf_Sym const *symp;
251 unsigned t;
252
253 for (symp = sym0, t = nsym; t; --t, ++symp) {
254 unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
255
256 if (txtndx == w2(symp->st_shndx)
257 /* avoid STB_WEAK */
258 && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
259 *recvalp = _w(symp->st_value);
260 return symp - sym0;
261 }
262 }
263 fprintf(stderr, "Cannot find symbol for section %d: %s.\n",
264 txtndx, txtname);
265 fail_file();
266}
267
268
269/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
270static char const *
271__has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */
272 Elf_Shdr const *const shdr0,
273 char const *const shstrtab,
274 char const *const fname)
275{
276 /* .sh_info depends on .sh_type == SHT_REL[,A] */
277 Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
278 char const *const txtname = &shstrtab[w(txthdr->sh_name)];
279
280 if (0 == strcmp("__mcount_loc", txtname)) {
281 fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
282 fname);
283 succeed_file();
284 }
285 if (SHT_PROGBITS != w(txthdr->sh_type) ||
286 !is_mcounted_section_name(txtname))
287 return NULL;
288 return txtname;
289}
290
291static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
292 Elf_Shdr const *const shdr0,
293 char const *const shstrtab,
294 char const *const fname)
295{
296 if (SHT_REL != w(relhdr->sh_type) && SHT_RELA != w(relhdr->sh_type))
297 return NULL;
298 return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
299}
300
301
302static unsigned tot_relsize(Elf_Shdr const *const shdr0,
303 unsigned nhdr,
304 const char *const shstrtab,
305 const char *const fname)
306{
307 unsigned totrelsz = 0;
308 Elf_Shdr const *shdrp = shdr0;
309
310 for (; nhdr; --nhdr, ++shdrp) {
311 if (has_rel_mcount(shdrp, shdr0, shstrtab, fname))
312 totrelsz += _w(shdrp->sh_size);
313 }
314 return totrelsz;
315}
316
317
318/* Overall supervision for Elf32 ET_REL file. */
319static void
320do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
321{
322 Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
323 + (void *)ehdr);
324 unsigned const nhdr = w2(ehdr->e_shnum);
325 Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)];
326 char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
327 + (void *)ehdr);
328
329 Elf_Shdr const *relhdr;
330 unsigned k;
331
332 /* Upper bound on space: assume all relevant relocs are for mcount. */
333 unsigned const totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
334 Elf_Rel *const mrel0 = umalloc(totrelsz);
335 Elf_Rel * mrelp = mrel0;
336
337 /* 2*sizeof(address) <= sizeof(Elf_Rel) */
338 uint_t *const mloc0 = umalloc(totrelsz>>1);
339 uint_t * mlocp = mloc0;
340
341 unsigned rel_entsize = 0;
342 unsigned symsec_sh_link = 0;
343
344 for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
345 char const *const txtname = has_rel_mcount(relhdr, shdr0,
346 shstrtab, fname);
347 if (txtname) {
348 uint_t recval = 0;
349 unsigned const recsym = find_secsym_ndx(
350 w(relhdr->sh_info), txtname, &recval,
351 &shdr0[symsec_sh_link = w(relhdr->sh_link)],
352 ehdr);
353
354 rel_entsize = _w(relhdr->sh_entsize);
355 mlocp = sift_rel_mcount(mlocp,
356 (void *)mlocp - (void *)mloc0, &mrelp,
357 relhdr, ehdr, recsym, recval, reltype);
358 }
359 }
360 if (mloc0 != mlocp) {
361 append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
362 rel_entsize, symsec_sh_link);
363 }
364 free(mrel0);
365 free(mloc0);
366}