14317cf95SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
2c28d5077SSteven Rostedt /*
3c28d5077SSteven Rostedt * recordmcount.h
4c28d5077SSteven Rostedt *
5c28d5077SSteven Rostedt * This code was taken out of recordmcount.c written by
6c28d5077SSteven Rostedt * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
7c28d5077SSteven Rostedt *
8c28d5077SSteven Rostedt * The original code had the same algorithms for both 32bit
9c28d5077SSteven Rostedt * and 64bit ELF files, but the code was duplicated to support
10c28d5077SSteven Rostedt * the difference in structures that were used. This
11c28d5077SSteven Rostedt * file creates a macro of everything that is different between
12c28d5077SSteven Rostedt * the 64 and 32 bit code, such that by including this header
13c28d5077SSteven Rostedt * twice we can create both sets of functions by including this
14c28d5077SSteven Rostedt * header once with RECORD_MCOUNT_64 undefined, and again with
15c28d5077SSteven Rostedt * it defined.
16c28d5077SSteven Rostedt *
17c28d5077SSteven Rostedt * This conversion to macros was done by:
18c28d5077SSteven Rostedt * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
19c28d5077SSteven Rostedt */
20c28d5077SSteven Rostedt #undef append_func
21412910cdSWu Zhangjin #undef is_fake_mcount
22412910cdSWu Zhangjin #undef fn_is_fake_mcount
23412910cdSWu Zhangjin #undef MIPS_is_fake_mcount
2407d8b595SMartin Schwidefsky #undef mcount_adjust
25c28d5077SSteven Rostedt #undef sift_rel_mcount
26ffd618faSSteven Rostedt #undef nop_mcount
27c28d5077SSteven Rostedt #undef find_secsym_ndx
28c28d5077SSteven Rostedt #undef __has_rel_mcount
29c28d5077SSteven Rostedt #undef has_rel_mcount
30c28d5077SSteven Rostedt #undef tot_relsize
3137762cb9SSteven Rostedt #undef get_mcountsym
324ef57b21SSami Tolvanen #undef find_symtab
334ef57b21SSami Tolvanen #undef get_shnum
344ef57b21SSami Tolvanen #undef set_shnum
354ef57b21SSami Tolvanen #undef get_shstrndx
364ef57b21SSami Tolvanen #undef get_symindex
3741b402a2SSteven Rostedt #undef get_sym_str_and_relp
38c28d5077SSteven Rostedt #undef do_func
39412910cdSWu Zhangjin #undef Elf_Addr
40c28d5077SSteven Rostedt #undef Elf_Ehdr
41c28d5077SSteven Rostedt #undef Elf_Shdr
42c28d5077SSteven Rostedt #undef Elf_Rel
43c28d5077SSteven Rostedt #undef Elf_Rela
44c28d5077SSteven Rostedt #undef Elf_Sym
45c28d5077SSteven Rostedt #undef ELF_R_SYM
46a2d49358SJohn Reiser #undef Elf_r_sym
47c28d5077SSteven Rostedt #undef ELF_R_INFO
48a2d49358SJohn Reiser #undef Elf_r_info
49c28d5077SSteven Rostedt #undef ELF_ST_BIND
509905ce8aSRabin Vincent #undef ELF_ST_TYPE
51a2d49358SJohn Reiser #undef fn_ELF_R_SYM
52a2d49358SJohn Reiser #undef fn_ELF_R_INFO
53c28d5077SSteven Rostedt #undef uint_t
54c28d5077SSteven Rostedt #undef _w
55c28d5077SSteven Rostedt #undef _align
56c28d5077SSteven Rostedt #undef _size
57c28d5077SSteven Rostedt
58c28d5077SSteven Rostedt #ifdef RECORD_MCOUNT_64
59c28d5077SSteven Rostedt # define append_func append64
60c28d5077SSteven Rostedt # define sift_rel_mcount sift64_rel_mcount
61ffd618faSSteven Rostedt # define nop_mcount nop_mcount_64
62c28d5077SSteven Rostedt # define find_secsym_ndx find64_secsym_ndx
63c28d5077SSteven Rostedt # define __has_rel_mcount __has64_rel_mcount
64c28d5077SSteven Rostedt # define has_rel_mcount has64_rel_mcount
65c28d5077SSteven Rostedt # define tot_relsize tot64_relsize
664ef57b21SSami Tolvanen # define find_symtab find_symtab64
674ef57b21SSami Tolvanen # define get_shnum get_shnum64
684ef57b21SSami Tolvanen # define set_shnum set_shnum64
694ef57b21SSami Tolvanen # define get_shstrndx get_shstrndx64
704ef57b21SSami Tolvanen # define get_symindex get_symindex64
7141b402a2SSteven Rostedt # define get_sym_str_and_relp get_sym_str_and_relp_64
72c28d5077SSteven Rostedt # define do_func do64
7337762cb9SSteven Rostedt # define get_mcountsym get_mcountsym_64
74412910cdSWu Zhangjin # define is_fake_mcount is_fake_mcount64
75412910cdSWu Zhangjin # define fn_is_fake_mcount fn_is_fake_mcount64
76412910cdSWu Zhangjin # define MIPS_is_fake_mcount MIPS64_is_fake_mcount
7707d8b595SMartin Schwidefsky # define mcount_adjust mcount_adjust_64
78412910cdSWu Zhangjin # define Elf_Addr Elf64_Addr
79c28d5077SSteven Rostedt # define Elf_Ehdr Elf64_Ehdr
80c28d5077SSteven Rostedt # define Elf_Shdr Elf64_Shdr
81c28d5077SSteven Rostedt # define Elf_Rel Elf64_Rel
82c28d5077SSteven Rostedt # define Elf_Rela Elf64_Rela
83c28d5077SSteven Rostedt # define Elf_Sym Elf64_Sym
84c28d5077SSteven Rostedt # define ELF_R_SYM ELF64_R_SYM
85a2d49358SJohn Reiser # define Elf_r_sym Elf64_r_sym
86c28d5077SSteven Rostedt # define ELF_R_INFO ELF64_R_INFO
87a2d49358SJohn Reiser # define Elf_r_info Elf64_r_info
88c28d5077SSteven Rostedt # define ELF_ST_BIND ELF64_ST_BIND
899905ce8aSRabin Vincent # define ELF_ST_TYPE ELF64_ST_TYPE
90a2d49358SJohn Reiser # define fn_ELF_R_SYM fn_ELF64_R_SYM
91a2d49358SJohn Reiser # define fn_ELF_R_INFO fn_ELF64_R_INFO
92c28d5077SSteven Rostedt # define uint_t uint64_t
93c28d5077SSteven Rostedt # define _w w8
94c28d5077SSteven Rostedt # define _align 7u
95c28d5077SSteven Rostedt # define _size 8
96c28d5077SSteven Rostedt #else
97c28d5077SSteven Rostedt # define append_func append32
98c28d5077SSteven Rostedt # define sift_rel_mcount sift32_rel_mcount
99ffd618faSSteven Rostedt # define nop_mcount nop_mcount_32
100c28d5077SSteven Rostedt # define find_secsym_ndx find32_secsym_ndx
101c28d5077SSteven Rostedt # define __has_rel_mcount __has32_rel_mcount
102c28d5077SSteven Rostedt # define has_rel_mcount has32_rel_mcount
103c28d5077SSteven Rostedt # define tot_relsize tot32_relsize
1044ef57b21SSami Tolvanen # define find_symtab find_symtab32
1054ef57b21SSami Tolvanen # define get_shnum get_shnum32
1064ef57b21SSami Tolvanen # define set_shnum set_shnum32
1074ef57b21SSami Tolvanen # define get_shstrndx get_shstrndx32
1084ef57b21SSami Tolvanen # define get_symindex get_symindex32
10941b402a2SSteven Rostedt # define get_sym_str_and_relp get_sym_str_and_relp_32
110c28d5077SSteven Rostedt # define do_func do32
11137762cb9SSteven Rostedt # define get_mcountsym get_mcountsym_32
112412910cdSWu Zhangjin # define is_fake_mcount is_fake_mcount32
113412910cdSWu Zhangjin # define fn_is_fake_mcount fn_is_fake_mcount32
114412910cdSWu Zhangjin # define MIPS_is_fake_mcount MIPS32_is_fake_mcount
11507d8b595SMartin Schwidefsky # define mcount_adjust mcount_adjust_32
116412910cdSWu Zhangjin # define Elf_Addr Elf32_Addr
117c28d5077SSteven Rostedt # define Elf_Ehdr Elf32_Ehdr
118c28d5077SSteven Rostedt # define Elf_Shdr Elf32_Shdr
119c28d5077SSteven Rostedt # define Elf_Rel Elf32_Rel
120c28d5077SSteven Rostedt # define Elf_Rela Elf32_Rela
121c28d5077SSteven Rostedt # define Elf_Sym Elf32_Sym
122c28d5077SSteven Rostedt # define ELF_R_SYM ELF32_R_SYM
123a2d49358SJohn Reiser # define Elf_r_sym Elf32_r_sym
124c28d5077SSteven Rostedt # define ELF_R_INFO ELF32_R_INFO
125a2d49358SJohn Reiser # define Elf_r_info Elf32_r_info
126c28d5077SSteven Rostedt # define ELF_ST_BIND ELF32_ST_BIND
1279905ce8aSRabin Vincent # define ELF_ST_TYPE ELF32_ST_TYPE
128a2d49358SJohn Reiser # define fn_ELF_R_SYM fn_ELF32_R_SYM
129a2d49358SJohn Reiser # define fn_ELF_R_INFO fn_ELF32_R_INFO
130c28d5077SSteven Rostedt # define uint_t uint32_t
131c28d5077SSteven Rostedt # define _w w
132c28d5077SSteven Rostedt # define _align 3u
133c28d5077SSteven Rostedt # define _size 4
134c28d5077SSteven Rostedt #endif
135c28d5077SSteven Rostedt
136412910cdSWu Zhangjin /* Functions and pointers that do_file() may override for specific e_machine. */
fn_is_fake_mcount(Elf_Rel const * rp)137412910cdSWu Zhangjin static int fn_is_fake_mcount(Elf_Rel const *rp)
138412910cdSWu Zhangjin {
139412910cdSWu Zhangjin return 0;
140412910cdSWu Zhangjin }
141412910cdSWu Zhangjin static int (*is_fake_mcount)(Elf_Rel const *rp) = fn_is_fake_mcount;
142412910cdSWu Zhangjin
fn_ELF_R_SYM(Elf_Rel const * rp)143a2d49358SJohn Reiser static uint_t fn_ELF_R_SYM(Elf_Rel const *rp)
144a2d49358SJohn Reiser {
145a2d49358SJohn Reiser return ELF_R_SYM(_w(rp->r_info));
146a2d49358SJohn Reiser }
147a2d49358SJohn Reiser static uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM;
148a2d49358SJohn Reiser
fn_ELF_R_INFO(Elf_Rel * const rp,unsigned sym,unsigned type)149a2d49358SJohn Reiser static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
150a2d49358SJohn Reiser {
151e63233f7SJohn Reiser rp->r_info = _w(ELF_R_INFO(sym, type));
152a2d49358SJohn Reiser }
153a2d49358SJohn Reiser static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;
154a2d49358SJohn Reiser
15507d8b595SMartin Schwidefsky static int mcount_adjust = 0;
15607d8b595SMartin Schwidefsky
157412910cdSWu Zhangjin /*
158412910cdSWu Zhangjin * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st
159412910cdSWu Zhangjin * _mcount symbol is needed for dynamic function tracer, with it, to disable
160412910cdSWu Zhangjin * tracing(ftrace_make_nop), the instruction in the position is replaced with
161412910cdSWu Zhangjin * the "b label" instruction, to enable tracing(ftrace_make_call), replace the
162412910cdSWu Zhangjin * instruction back. So, here, we set the 2nd one as fake and filter it.
163412910cdSWu Zhangjin *
164412910cdSWu Zhangjin * c: 3c030000 lui v1,0x0 <--> b label
165412910cdSWu Zhangjin * c: R_MIPS_HI16 _mcount
166412910cdSWu Zhangjin * c: R_MIPS_NONE *ABS*
167412910cdSWu Zhangjin * c: R_MIPS_NONE *ABS*
168412910cdSWu Zhangjin * 10: 64630000 daddiu v1,v1,0
169412910cdSWu Zhangjin * 10: R_MIPS_LO16 _mcount
170412910cdSWu Zhangjin * 10: R_MIPS_NONE *ABS*
171412910cdSWu Zhangjin * 10: R_MIPS_NONE *ABS*
172412910cdSWu Zhangjin * 14: 03e0082d move at,ra
173412910cdSWu Zhangjin * 18: 0060f809 jalr v1
174412910cdSWu Zhangjin * label:
175412910cdSWu Zhangjin */
176412910cdSWu Zhangjin #define MIPS_FAKEMCOUNT_OFFSET 4
177412910cdSWu Zhangjin
MIPS_is_fake_mcount(Elf_Rel const * rp)178412910cdSWu Zhangjin static int MIPS_is_fake_mcount(Elf_Rel const *rp)
179412910cdSWu Zhangjin {
18091ad11d7SAlex Smith static Elf_Addr old_r_offset = ~(Elf_Addr)0;
181412910cdSWu Zhangjin Elf_Addr current_r_offset = _w(rp->r_offset);
182412910cdSWu Zhangjin int is_fake;
183412910cdSWu Zhangjin
18491ad11d7SAlex Smith is_fake = (old_r_offset != ~(Elf_Addr)0) &&
185412910cdSWu Zhangjin (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET);
186412910cdSWu Zhangjin old_r_offset = current_r_offset;
187412910cdSWu Zhangjin
188412910cdSWu Zhangjin return is_fake;
189412910cdSWu Zhangjin }
190a2d49358SJohn Reiser
get_symindex(Elf_Sym const * sym,Elf32_Word const * symtab,Elf32_Word const * symtab_shndx)1914ef57b21SSami Tolvanen static unsigned int get_symindex(Elf_Sym const *sym, Elf32_Word const *symtab,
1924ef57b21SSami Tolvanen Elf32_Word const *symtab_shndx)
1934ef57b21SSami Tolvanen {
1944ef57b21SSami Tolvanen unsigned long offset;
195*fb780761SPeter Zijlstra unsigned short shndx = w2(sym->st_shndx);
1964ef57b21SSami Tolvanen int index;
1974ef57b21SSami Tolvanen
198*fb780761SPeter Zijlstra if (shndx > SHN_UNDEF && shndx < SHN_LORESERVE)
199*fb780761SPeter Zijlstra return shndx;
2004ef57b21SSami Tolvanen
201*fb780761SPeter Zijlstra if (shndx == SHN_XINDEX) {
2024ef57b21SSami Tolvanen offset = (unsigned long)sym - (unsigned long)symtab;
2034ef57b21SSami Tolvanen index = offset / sizeof(*sym);
2044ef57b21SSami Tolvanen
2054ef57b21SSami Tolvanen return w(symtab_shndx[index]);
2064ef57b21SSami Tolvanen }
2074ef57b21SSami Tolvanen
208*fb780761SPeter Zijlstra return 0;
209*fb780761SPeter Zijlstra }
210*fb780761SPeter Zijlstra
get_shnum(Elf_Ehdr const * ehdr,Elf_Shdr const * shdr0)2114ef57b21SSami Tolvanen static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
2124ef57b21SSami Tolvanen {
2134ef57b21SSami Tolvanen if (shdr0 && !ehdr->e_shnum)
2144ef57b21SSami Tolvanen return w(shdr0->sh_size);
2154ef57b21SSami Tolvanen
2164ef57b21SSami Tolvanen return w2(ehdr->e_shnum);
2174ef57b21SSami Tolvanen }
2184ef57b21SSami Tolvanen
set_shnum(Elf_Ehdr * ehdr,Elf_Shdr * shdr0,unsigned int new_shnum)2194ef57b21SSami Tolvanen static void set_shnum(Elf_Ehdr *ehdr, Elf_Shdr *shdr0, unsigned int new_shnum)
2204ef57b21SSami Tolvanen {
2214ef57b21SSami Tolvanen if (new_shnum >= SHN_LORESERVE) {
2224ef57b21SSami Tolvanen ehdr->e_shnum = 0;
2234ef57b21SSami Tolvanen shdr0->sh_size = w(new_shnum);
2244ef57b21SSami Tolvanen } else
2254ef57b21SSami Tolvanen ehdr->e_shnum = w2(new_shnum);
2264ef57b21SSami Tolvanen }
2274ef57b21SSami Tolvanen
get_shstrndx(Elf_Ehdr const * ehdr,Elf_Shdr const * shdr0)2284ef57b21SSami Tolvanen static int get_shstrndx(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
2294ef57b21SSami Tolvanen {
2304ef57b21SSami Tolvanen if (ehdr->e_shstrndx != SHN_XINDEX)
2314ef57b21SSami Tolvanen return w2(ehdr->e_shstrndx);
2324ef57b21SSami Tolvanen
2334ef57b21SSami Tolvanen return w(shdr0->sh_link);
2344ef57b21SSami Tolvanen }
2354ef57b21SSami Tolvanen
find_symtab(Elf_Ehdr * const ehdr,Elf_Shdr const * shdr0,unsigned const nhdr,Elf32_Word ** symtab,Elf32_Word ** symtab_shndx)2364ef57b21SSami Tolvanen static void find_symtab(Elf_Ehdr *const ehdr, Elf_Shdr const *shdr0,
2374ef57b21SSami Tolvanen unsigned const nhdr, Elf32_Word **symtab,
2384ef57b21SSami Tolvanen Elf32_Word **symtab_shndx)
2394ef57b21SSami Tolvanen {
2404ef57b21SSami Tolvanen Elf_Shdr const *relhdr;
2414ef57b21SSami Tolvanen unsigned k;
2424ef57b21SSami Tolvanen
2434ef57b21SSami Tolvanen *symtab = NULL;
2444ef57b21SSami Tolvanen *symtab_shndx = NULL;
2454ef57b21SSami Tolvanen
2464ef57b21SSami Tolvanen for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
2474ef57b21SSami Tolvanen if (relhdr->sh_type == SHT_SYMTAB)
2484ef57b21SSami Tolvanen *symtab = (void *)ehdr + relhdr->sh_offset;
2494ef57b21SSami Tolvanen else if (relhdr->sh_type == SHT_SYMTAB_SHNDX)
2504ef57b21SSami Tolvanen *symtab_shndx = (void *)ehdr + relhdr->sh_offset;
2514ef57b21SSami Tolvanen
2524ef57b21SSami Tolvanen if (*symtab && *symtab_shndx)
2534ef57b21SSami Tolvanen break;
2544ef57b21SSami Tolvanen }
2554ef57b21SSami Tolvanen }
2564ef57b21SSami Tolvanen
257c28d5077SSteven Rostedt /* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
append_func(Elf_Ehdr * const ehdr,Elf_Shdr * const shstr,uint_t const * const mloc0,uint_t const * const mlocp,Elf_Rel const * const mrel0,Elf_Rel const * const mrelp,unsigned int const rel_entsize,unsigned int const symsec_sh_link)2583f1df120SMatt Helsley static int append_func(Elf_Ehdr *const ehdr,
259c28d5077SSteven Rostedt Elf_Shdr *const shstr,
260c28d5077SSteven Rostedt uint_t const *const mloc0,
261c28d5077SSteven Rostedt uint_t const *const mlocp,
262c28d5077SSteven Rostedt Elf_Rel const *const mrel0,
263c28d5077SSteven Rostedt Elf_Rel const *const mrelp,
264c28d5077SSteven Rostedt unsigned int const rel_entsize,
265c28d5077SSteven Rostedt unsigned int const symsec_sh_link)
266c28d5077SSteven Rostedt {
267c28d5077SSteven Rostedt /* Begin constructing output file */
268c28d5077SSteven Rostedt Elf_Shdr mcsec;
269c28d5077SSteven Rostedt char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
270c28d5077SSteven Rostedt ? ".rela__mcount_loc"
271c28d5077SSteven Rostedt : ".rel__mcount_loc";
272c28d5077SSteven Rostedt uint_t const old_shoff = _w(ehdr->e_shoff);
273c28d5077SSteven Rostedt uint_t const old_shstr_sh_size = _w(shstr->sh_size);
274c28d5077SSteven Rostedt uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
2754ef57b21SSami Tolvanen Elf_Shdr *const shdr0 = (Elf_Shdr *)(old_shoff + (void *)ehdr);
2764ef57b21SSami Tolvanen unsigned int const old_shnum = get_shnum(ehdr, shdr0);
2774ef57b21SSami Tolvanen unsigned int const new_shnum = 2 + old_shnum; /* {.rel,}__mcount_loc */
278c28d5077SSteven Rostedt uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
279c28d5077SSteven Rostedt uint_t new_e_shoff;
280c28d5077SSteven Rostedt
281c28d5077SSteven Rostedt shstr->sh_size = _w(t);
282c28d5077SSteven Rostedt shstr->sh_offset = _w(sb.st_size);
283c28d5077SSteven Rostedt t += sb.st_size;
284c28d5077SSteven Rostedt t += (_align & -t); /* word-byte align */
285c28d5077SSteven Rostedt new_e_shoff = t;
286c28d5077SSteven Rostedt
2874ef57b21SSami Tolvanen set_shnum(ehdr, shdr0, new_shnum);
2884ef57b21SSami Tolvanen
289c28d5077SSteven Rostedt /* body for new shstrtab */
2903f1df120SMatt Helsley if (ulseek(sb.st_size, SEEK_SET) < 0)
2913f1df120SMatt Helsley return -1;
2923f1df120SMatt Helsley if (uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size) < 0)
2933f1df120SMatt Helsley return -1;
2943f1df120SMatt Helsley if (uwrite(mc_name, 1 + strlen(mc_name)) < 0)
2953f1df120SMatt Helsley return -1;
296c28d5077SSteven Rostedt
297c28d5077SSteven Rostedt /* old(modified) Elf_Shdr table, word-byte aligned */
2983f1df120SMatt Helsley if (ulseek(t, SEEK_SET) < 0)
2993f1df120SMatt Helsley return -1;
300c28d5077SSteven Rostedt t += sizeof(Elf_Shdr) * old_shnum;
3013f1df120SMatt Helsley if (uwrite(old_shoff + (void *)ehdr,
3023f1df120SMatt Helsley sizeof(Elf_Shdr) * old_shnum) < 0)
3033f1df120SMatt Helsley return -1;
304c28d5077SSteven Rostedt
305c28d5077SSteven Rostedt /* new sections __mcount_loc and .rel__mcount_loc */
306c28d5077SSteven Rostedt t += 2*sizeof(mcsec);
307c28d5077SSteven Rostedt mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel")
308c28d5077SSteven Rostedt + old_shstr_sh_size);
309c28d5077SSteven Rostedt mcsec.sh_type = w(SHT_PROGBITS);
310c28d5077SSteven Rostedt mcsec.sh_flags = _w(SHF_ALLOC);
311c28d5077SSteven Rostedt mcsec.sh_addr = 0;
312c28d5077SSteven Rostedt mcsec.sh_offset = _w(t);
313c28d5077SSteven Rostedt mcsec.sh_size = _w((void *)mlocp - (void *)mloc0);
314c28d5077SSteven Rostedt mcsec.sh_link = 0;
315c28d5077SSteven Rostedt mcsec.sh_info = 0;
316c28d5077SSteven Rostedt mcsec.sh_addralign = _w(_size);
317c28d5077SSteven Rostedt mcsec.sh_entsize = _w(_size);
3183f1df120SMatt Helsley if (uwrite(&mcsec, sizeof(mcsec)) < 0)
3193f1df120SMatt Helsley return -1;
320c28d5077SSteven Rostedt
321c28d5077SSteven Rostedt mcsec.sh_name = w(old_shstr_sh_size);
322c28d5077SSteven Rostedt mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
323c28d5077SSteven Rostedt ? w(SHT_RELA)
324c28d5077SSteven Rostedt : w(SHT_REL);
325c28d5077SSteven Rostedt mcsec.sh_flags = 0;
326c28d5077SSteven Rostedt mcsec.sh_addr = 0;
327c28d5077SSteven Rostedt mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t);
328c28d5077SSteven Rostedt mcsec.sh_size = _w((void *)mrelp - (void *)mrel0);
329c28d5077SSteven Rostedt mcsec.sh_link = w(symsec_sh_link);
330c28d5077SSteven Rostedt mcsec.sh_info = w(old_shnum);
331c28d5077SSteven Rostedt mcsec.sh_addralign = _w(_size);
332c28d5077SSteven Rostedt mcsec.sh_entsize = _w(rel_entsize);
333c28d5077SSteven Rostedt
3343f1df120SMatt Helsley if (uwrite(&mcsec, sizeof(mcsec)) < 0)
3353f1df120SMatt Helsley return -1;
3363f1df120SMatt Helsley
3373f1df120SMatt Helsley if (uwrite(mloc0, (void *)mlocp - (void *)mloc0) < 0)
3383f1df120SMatt Helsley return -1;
3393f1df120SMatt Helsley if (uwrite(mrel0, (void *)mrelp - (void *)mrel0) < 0)
3403f1df120SMatt Helsley return -1;
341c28d5077SSteven Rostedt
342c28d5077SSteven Rostedt ehdr->e_shoff = _w(new_e_shoff);
3433f1df120SMatt Helsley if (ulseek(0, SEEK_SET) < 0)
3443f1df120SMatt Helsley return -1;
3453f1df120SMatt Helsley if (uwrite(ehdr, sizeof(*ehdr)) < 0)
3463f1df120SMatt Helsley return -1;
3473f1df120SMatt Helsley return 0;
348c28d5077SSteven Rostedt }
349c28d5077SSteven Rostedt
get_mcountsym(Elf_Sym const * const sym0,Elf_Rel const * relp,char const * const str0)35037762cb9SSteven Rostedt static unsigned get_mcountsym(Elf_Sym const *const sym0,
35137762cb9SSteven Rostedt Elf_Rel const *relp,
35237762cb9SSteven Rostedt char const *const str0)
35337762cb9SSteven Rostedt {
35437762cb9SSteven Rostedt unsigned mcountsym = 0;
35537762cb9SSteven Rostedt
35637762cb9SSteven Rostedt Elf_Sym const *const symp =
35737762cb9SSteven Rostedt &sym0[Elf_r_sym(relp)];
35837762cb9SSteven Rostedt char const *symname = &str0[w(symp->st_name)];
35937762cb9SSteven Rostedt char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
36048bb5dc6SSteven Rostedt char const *fentry = "__fentry__";
36137762cb9SSteven Rostedt
36237762cb9SSteven Rostedt if (symname[0] == '.')
36337762cb9SSteven Rostedt ++symname; /* ppc64 hack */
36437762cb9SSteven Rostedt if (strcmp(mcount, symname) == 0 ||
36548bb5dc6SSteven Rostedt (altmcount && strcmp(altmcount, symname) == 0) ||
36648bb5dc6SSteven Rostedt (strcmp(fentry, symname) == 0))
36737762cb9SSteven Rostedt mcountsym = Elf_r_sym(relp);
36837762cb9SSteven Rostedt
36937762cb9SSteven Rostedt return mcountsym;
37037762cb9SSteven Rostedt }
37137762cb9SSteven Rostedt
get_sym_str_and_relp(Elf_Shdr const * const relhdr,Elf_Ehdr const * const ehdr,Elf_Sym const ** sym0,char const ** str0,Elf_Rel const ** relp)37241b402a2SSteven Rostedt static void get_sym_str_and_relp(Elf_Shdr const *const relhdr,
37341b402a2SSteven Rostedt Elf_Ehdr const *const ehdr,
37441b402a2SSteven Rostedt Elf_Sym const **sym0,
37541b402a2SSteven Rostedt char const **str0,
37641b402a2SSteven Rostedt Elf_Rel const **relp)
37741b402a2SSteven Rostedt {
37841b402a2SSteven Rostedt Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
37941b402a2SSteven Rostedt + (void *)ehdr);
38041b402a2SSteven Rostedt unsigned const symsec_sh_link = w(relhdr->sh_link);
38141b402a2SSteven Rostedt Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
38241b402a2SSteven Rostedt Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
38341b402a2SSteven Rostedt Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
38441b402a2SSteven Rostedt + (void *)ehdr);
38541b402a2SSteven Rostedt
38641b402a2SSteven Rostedt *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
38741b402a2SSteven Rostedt + (void *)ehdr);
38841b402a2SSteven Rostedt
38941b402a2SSteven Rostedt *str0 = (char const *)(_w(strsec->sh_offset)
39041b402a2SSteven Rostedt + (void *)ehdr);
39141b402a2SSteven Rostedt
39241b402a2SSteven Rostedt *relp = rel0;
39341b402a2SSteven Rostedt }
39441b402a2SSteven Rostedt
395c28d5077SSteven Rostedt /*
396c28d5077SSteven Rostedt * Look at the relocations in order to find the calls to mcount.
397c28d5077SSteven Rostedt * Accumulate the section offsets that are found, and their relocation info,
398c28d5077SSteven Rostedt * onto the end of the existing arrays.
399c28d5077SSteven Rostedt */
sift_rel_mcount(uint_t * mlocp,unsigned const offbase,Elf_Rel ** const mrelpp,Elf_Shdr const * const relhdr,Elf_Ehdr const * const ehdr,unsigned const recsym,uint_t const recval,unsigned const reltype)400c28d5077SSteven Rostedt static uint_t *sift_rel_mcount(uint_t *mlocp,
401c28d5077SSteven Rostedt unsigned const offbase,
402c28d5077SSteven Rostedt Elf_Rel **const mrelpp,
403c28d5077SSteven Rostedt Elf_Shdr const *const relhdr,
404c28d5077SSteven Rostedt Elf_Ehdr const *const ehdr,
405c28d5077SSteven Rostedt unsigned const recsym,
406c28d5077SSteven Rostedt uint_t const recval,
407c28d5077SSteven Rostedt unsigned const reltype)
408c28d5077SSteven Rostedt {
409c28d5077SSteven Rostedt uint_t *const mloc0 = mlocp;
410c28d5077SSteven Rostedt Elf_Rel *mrelp = *mrelpp;
41141b402a2SSteven Rostedt Elf_Sym const *sym0;
41241b402a2SSteven Rostedt char const *str0;
41341b402a2SSteven Rostedt Elf_Rel const *relp;
414c28d5077SSteven Rostedt unsigned rel_entsize = _w(relhdr->sh_entsize);
415c28d5077SSteven Rostedt unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
416c28d5077SSteven Rostedt unsigned mcountsym = 0;
417c28d5077SSteven Rostedt unsigned t;
418c28d5077SSteven Rostedt
41941b402a2SSteven Rostedt get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
42041b402a2SSteven Rostedt
421c28d5077SSteven Rostedt for (t = nrel; t; --t) {
42237762cb9SSteven Rostedt if (!mcountsym)
42337762cb9SSteven Rostedt mcountsym = get_mcountsym(sym0, relp, str0);
424c28d5077SSteven Rostedt
42580e5302eSNaveen N. Rao if (mcountsym && mcountsym == Elf_r_sym(relp) &&
42680e5302eSNaveen N. Rao !is_fake_mcount(relp)) {
42707d8b595SMartin Schwidefsky uint_t const addend =
42807d8b595SMartin Schwidefsky _w(_w(relp->r_offset) - recval + mcount_adjust);
429c28d5077SSteven Rostedt mrelp->r_offset = _w(offbase
430c28d5077SSteven Rostedt + ((void *)mlocp - (void *)mloc0));
431a2d49358SJohn Reiser Elf_r_info(mrelp, recsym, reltype);
432dd5477ffSSteven Rostedt if (rel_entsize == sizeof(Elf_Rela)) {
433c28d5077SSteven Rostedt ((Elf_Rela *)mrelp)->r_addend = addend;
434c28d5077SSteven Rostedt *mlocp++ = 0;
435c28d5077SSteven Rostedt } else
436c28d5077SSteven Rostedt *mlocp++ = addend;
437c28d5077SSteven Rostedt
438c28d5077SSteven Rostedt mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
439c28d5077SSteven Rostedt }
440c28d5077SSteven Rostedt relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
441c28d5077SSteven Rostedt }
442c28d5077SSteven Rostedt *mrelpp = mrelp;
443c28d5077SSteven Rostedt return mlocp;
444c28d5077SSteven Rostedt }
445c28d5077SSteven Rostedt
446ffd618faSSteven Rostedt /*
447ffd618faSSteven Rostedt * Read the relocation table again, but this time its called on sections
448ffd618faSSteven Rostedt * that are not going to be traced. The mcount calls here will be converted
449ffd618faSSteven Rostedt * into nops.
450ffd618faSSteven Rostedt */
nop_mcount(Elf_Shdr const * const relhdr,Elf_Ehdr const * const ehdr,const char * const txtname)4513f1df120SMatt Helsley static int nop_mcount(Elf_Shdr const *const relhdr,
452dfad3d59SSteven Rostedt Elf_Ehdr const *const ehdr,
453dfad3d59SSteven Rostedt const char *const txtname)
454ffd618faSSteven Rostedt {
455ffd618faSSteven Rostedt Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
456ffd618faSSteven Rostedt + (void *)ehdr);
45741b402a2SSteven Rostedt Elf_Sym const *sym0;
45841b402a2SSteven Rostedt char const *str0;
45941b402a2SSteven Rostedt Elf_Rel const *relp;
46041b402a2SSteven Rostedt Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)];
461ffd618faSSteven Rostedt unsigned rel_entsize = _w(relhdr->sh_entsize);
462ffd618faSSteven Rostedt unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
463ffd618faSSteven Rostedt unsigned mcountsym = 0;
464ffd618faSSteven Rostedt unsigned t;
465dfad3d59SSteven Rostedt int once = 0;
466ffd618faSSteven Rostedt
46741b402a2SSteven Rostedt get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
46841b402a2SSteven Rostedt
469ffd618faSSteven Rostedt for (t = nrel; t; --t) {
470ffd618faSSteven Rostedt int ret = -1;
471ffd618faSSteven Rostedt
47237762cb9SSteven Rostedt if (!mcountsym)
47337762cb9SSteven Rostedt mcountsym = get_mcountsym(sym0, relp, str0);
474ffd618faSSteven Rostedt
475dfad3d59SSteven Rostedt if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
4767f8557b8SSteven Rostedt (VMware) if (make_nop)
477c84da8b9Slibin ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset));
478dfad3d59SSteven Rostedt if (warn_on_notrace_sect && !once) {
479dfad3d59SSteven Rostedt printf("Section %s has mcount callers being ignored\n",
480dfad3d59SSteven Rostedt txtname);
481dfad3d59SSteven Rostedt once = 1;
482dfad3d59SSteven Rostedt /* just warn? */
483dfad3d59SSteven Rostedt if (!make_nop)
4843f1df120SMatt Helsley return 0;
485dfad3d59SSteven Rostedt }
486dfad3d59SSteven Rostedt }
487ffd618faSSteven Rostedt
488ffd618faSSteven Rostedt /*
489ffd618faSSteven Rostedt * If we successfully removed the mcount, mark the relocation
490ffd618faSSteven Rostedt * as a nop (don't do anything with it).
491ffd618faSSteven Rostedt */
492ffd618faSSteven Rostedt if (!ret) {
493ffd618faSSteven Rostedt Elf_Rel rel;
494ffd618faSSteven Rostedt rel = *(Elf_Rel *)relp;
495ffd618faSSteven Rostedt Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
4963f1df120SMatt Helsley if (ulseek((void *)relp - (void *)ehdr, SEEK_SET) < 0)
4973f1df120SMatt Helsley return -1;
4983f1df120SMatt Helsley if (uwrite(&rel, sizeof(rel)) < 0)
4993f1df120SMatt Helsley return -1;
500ffd618faSSteven Rostedt }
501ffd618faSSteven Rostedt relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
502ffd618faSSteven Rostedt }
5033f1df120SMatt Helsley return 0;
504ffd618faSSteven Rostedt }
505ffd618faSSteven Rostedt
506c28d5077SSteven Rostedt /*
507c28d5077SSteven Rostedt * Find a symbol in the given section, to be used as the base for relocating
508c28d5077SSteven Rostedt * the table of offsets of calls to mcount. A local or global symbol suffices,
509c28d5077SSteven Rostedt * but avoid a Weak symbol because it may be overridden; the change in value
510c28d5077SSteven Rostedt * would invalidate the relocations of the offsets of the calls to mcount.
511c28d5077SSteven Rostedt * Often the found symbol will be the unnamed local symbol generated by
512c28d5077SSteven Rostedt * GNU 'as' for the start of each section. For example:
513c28d5077SSteven Rostedt * Num: Value Size Type Bind Vis Ndx Name
514c28d5077SSteven Rostedt * 2: 00000000 0 SECTION LOCAL DEFAULT 1
515c28d5077SSteven Rostedt */
find_secsym_ndx(unsigned const txtndx,char const * const txtname,uint_t * const recvalp,unsigned int * sym_index,Elf_Shdr const * const symhdr,Elf32_Word const * symtab,Elf32_Word const * symtab_shndx,Elf_Ehdr const * const ehdr)5163f1df120SMatt Helsley static int find_secsym_ndx(unsigned const txtndx,
517c28d5077SSteven Rostedt char const *const txtname,
518c28d5077SSteven Rostedt uint_t *const recvalp,
5193f1df120SMatt Helsley unsigned int *sym_index,
520c28d5077SSteven Rostedt Elf_Shdr const *const symhdr,
5214ef57b21SSami Tolvanen Elf32_Word const *symtab,
5224ef57b21SSami Tolvanen Elf32_Word const *symtab_shndx,
523c28d5077SSteven Rostedt Elf_Ehdr const *const ehdr)
524c28d5077SSteven Rostedt {
525c28d5077SSteven Rostedt Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
526c28d5077SSteven Rostedt + (void *)ehdr);
527c28d5077SSteven Rostedt unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize);
528c28d5077SSteven Rostedt Elf_Sym const *symp;
529c28d5077SSteven Rostedt unsigned t;
530c28d5077SSteven Rostedt
531c28d5077SSteven Rostedt for (symp = sym0, t = nsym; t; --t, ++symp) {
532c28d5077SSteven Rostedt unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
533c28d5077SSteven Rostedt
5344ef57b21SSami Tolvanen if (txtndx == get_symindex(symp, symtab, symtab_shndx)
535c28d5077SSteven Rostedt /* avoid STB_WEAK */
536c28d5077SSteven Rostedt && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
5379905ce8aSRabin Vincent /* function symbols on ARM have quirks, avoid them */
5389905ce8aSRabin Vincent if (w2(ehdr->e_machine) == EM_ARM
5399905ce8aSRabin Vincent && ELF_ST_TYPE(symp->st_info) == STT_FUNC)
5409905ce8aSRabin Vincent continue;
5419905ce8aSRabin Vincent
542c28d5077SSteven Rostedt *recvalp = _w(symp->st_value);
5433f1df120SMatt Helsley *sym_index = symp - sym0;
5443f1df120SMatt Helsley return 0;
545c28d5077SSteven Rostedt }
546c28d5077SSteven Rostedt }
547ac5db1fcSnixiaoming fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
548c28d5077SSteven Rostedt txtndx, txtname);
5493f1df120SMatt Helsley return -1;
550c28d5077SSteven Rostedt }
551c28d5077SSteven Rostedt
552c28d5077SSteven Rostedt /* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
__has_rel_mcount(Elf_Shdr const * const relhdr,Elf_Shdr const * const shdr0,char const * const shstrtab,char const * const fname)5533aec8638SMatt Helsley static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
554c28d5077SSteven Rostedt Elf_Shdr const *const shdr0,
555c28d5077SSteven Rostedt char const *const shstrtab,
556c28d5077SSteven Rostedt char const *const fname)
557c28d5077SSteven Rostedt {
558c28d5077SSteven Rostedt /* .sh_info depends on .sh_type == SHT_REL[,A] */
559c28d5077SSteven Rostedt Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
560c28d5077SSteven Rostedt char const *const txtname = &shstrtab[w(txthdr->sh_name)];
561c28d5077SSteven Rostedt
562dd5477ffSSteven Rostedt if (strcmp("__mcount_loc", txtname) == 0) {
563c28d5077SSteven Rostedt fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
564c28d5077SSteven Rostedt fname);
5653f1df120SMatt Helsley return already_has_rel_mcount;
566c28d5077SSteven Rostedt }
567dd5477ffSSteven Rostedt if (w(txthdr->sh_type) != SHT_PROGBITS ||
5682e885057SDavid Daney !(_w(txthdr->sh_flags) & SHF_EXECINSTR))
569c28d5077SSteven Rostedt return NULL;
570c28d5077SSteven Rostedt return txtname;
571c28d5077SSteven Rostedt }
572c28d5077SSteven Rostedt
has_rel_mcount(Elf_Shdr const * const relhdr,Elf_Shdr const * const shdr0,char const * const shstrtab,char const * const fname)573c28d5077SSteven Rostedt static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
574c28d5077SSteven Rostedt Elf_Shdr const *const shdr0,
575c28d5077SSteven Rostedt char const *const shstrtab,
576c28d5077SSteven Rostedt char const *const fname)
577c28d5077SSteven Rostedt {
578dd5477ffSSteven Rostedt if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA)
579c28d5077SSteven Rostedt return NULL;
580c28d5077SSteven Rostedt return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
581c28d5077SSteven Rostedt }
582c28d5077SSteven Rostedt
583c28d5077SSteven Rostedt
tot_relsize(Elf_Shdr const * const shdr0,unsigned nhdr,const char * const shstrtab,const char * const fname)584c28d5077SSteven Rostedt static unsigned tot_relsize(Elf_Shdr const *const shdr0,
585c28d5077SSteven Rostedt unsigned nhdr,
586c28d5077SSteven Rostedt const char *const shstrtab,
587c28d5077SSteven Rostedt const char *const fname)
588c28d5077SSteven Rostedt {
589c28d5077SSteven Rostedt unsigned totrelsz = 0;
590c28d5077SSteven Rostedt Elf_Shdr const *shdrp = shdr0;
591ffd618faSSteven Rostedt char const *txtname;
592c28d5077SSteven Rostedt
593c28d5077SSteven Rostedt for (; nhdr; --nhdr, ++shdrp) {
594ffd618faSSteven Rostedt txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
5953f1df120SMatt Helsley if (txtname == already_has_rel_mcount) {
5963f1df120SMatt Helsley totrelsz = 0;
5973f1df120SMatt Helsley break;
5983f1df120SMatt Helsley }
599ffd618faSSteven Rostedt if (txtname && is_mcounted_section_name(txtname))
600c28d5077SSteven Rostedt totrelsz += _w(shdrp->sh_size);
601c28d5077SSteven Rostedt }
602c28d5077SSteven Rostedt return totrelsz;
603c28d5077SSteven Rostedt }
604c28d5077SSteven Rostedt
605c28d5077SSteven Rostedt /* Overall supervision for Elf32 ET_REL file. */
do_func(Elf_Ehdr * const ehdr,char const * const fname,unsigned const reltype)6063aec8638SMatt Helsley static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
6073aec8638SMatt Helsley unsigned const reltype)
608c28d5077SSteven Rostedt {
609c28d5077SSteven Rostedt Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
610c28d5077SSteven Rostedt + (void *)ehdr);
6114ef57b21SSami Tolvanen unsigned const nhdr = get_shnum(ehdr, shdr0);
6124ef57b21SSami Tolvanen Elf_Shdr *const shstr = &shdr0[get_shstrndx(ehdr, shdr0)];
613c28d5077SSteven Rostedt char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
614c28d5077SSteven Rostedt + (void *)ehdr);
615c28d5077SSteven Rostedt
616c28d5077SSteven Rostedt Elf_Shdr const *relhdr;
617c28d5077SSteven Rostedt unsigned k;
618c28d5077SSteven Rostedt
6194ef57b21SSami Tolvanen Elf32_Word *symtab;
6204ef57b21SSami Tolvanen Elf32_Word *symtab_shndx;
6214ef57b21SSami Tolvanen
622c28d5077SSteven Rostedt /* Upper bound on space: assume all relevant relocs are for mcount. */
6233f1df120SMatt Helsley unsigned totrelsz;
624c28d5077SSteven Rostedt
6253f1df120SMatt Helsley Elf_Rel * mrel0;
6263f1df120SMatt Helsley Elf_Rel * mrelp;
6273f1df120SMatt Helsley
6283f1df120SMatt Helsley uint_t * mloc0;
6293f1df120SMatt Helsley uint_t * mlocp;
630c28d5077SSteven Rostedt
631c28d5077SSteven Rostedt unsigned rel_entsize = 0;
632c28d5077SSteven Rostedt unsigned symsec_sh_link = 0;
633c28d5077SSteven Rostedt
6343f1df120SMatt Helsley int result = 0;
6353f1df120SMatt Helsley
6363f1df120SMatt Helsley totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
6373f1df120SMatt Helsley if (totrelsz == 0)
6383f1df120SMatt Helsley return 0;
6393f1df120SMatt Helsley mrel0 = umalloc(totrelsz);
6403f1df120SMatt Helsley mrelp = mrel0;
6413f1df120SMatt Helsley if (!mrel0)
6423f1df120SMatt Helsley return -1;
6433f1df120SMatt Helsley
6443f1df120SMatt Helsley /* 2*sizeof(address) <= sizeof(Elf_Rel) */
6453f1df120SMatt Helsley mloc0 = umalloc(totrelsz>>1);
6463f1df120SMatt Helsley mlocp = mloc0;
6473f1df120SMatt Helsley if (!mloc0) {
6483f1df120SMatt Helsley free(mrel0);
6493f1df120SMatt Helsley return -1;
6503f1df120SMatt Helsley }
6513f1df120SMatt Helsley
6524ef57b21SSami Tolvanen find_symtab(ehdr, shdr0, nhdr, &symtab, &symtab_shndx);
6534ef57b21SSami Tolvanen
654c28d5077SSteven Rostedt for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
655c28d5077SSteven Rostedt char const *const txtname = has_rel_mcount(relhdr, shdr0,
656c28d5077SSteven Rostedt shstrtab, fname);
6573f1df120SMatt Helsley if (txtname == already_has_rel_mcount) {
6583f1df120SMatt Helsley result = 0;
6593f1df120SMatt Helsley file_updated = 0;
6603f1df120SMatt Helsley goto out; /* Nothing to be done; don't append! */
6613f1df120SMatt Helsley }
662ffd618faSSteven Rostedt if (txtname && is_mcounted_section_name(txtname)) {
6633f1df120SMatt Helsley unsigned int recsym;
664c28d5077SSteven Rostedt uint_t recval = 0;
6653f1df120SMatt Helsley
6663f1df120SMatt Helsley symsec_sh_link = w(relhdr->sh_link);
6673f1df120SMatt Helsley result = find_secsym_ndx(w(relhdr->sh_info), txtname,
6683f1df120SMatt Helsley &recval, &recsym,
6693f1df120SMatt Helsley &shdr0[symsec_sh_link],
6704ef57b21SSami Tolvanen symtab, symtab_shndx,
671c28d5077SSteven Rostedt ehdr);
6723f1df120SMatt Helsley if (result)
6733f1df120SMatt Helsley goto out;
674c28d5077SSteven Rostedt
675c28d5077SSteven Rostedt rel_entsize = _w(relhdr->sh_entsize);
676c28d5077SSteven Rostedt mlocp = sift_rel_mcount(mlocp,
677c28d5077SSteven Rostedt (void *)mlocp - (void *)mloc0, &mrelp,
678c28d5077SSteven Rostedt relhdr, ehdr, recsym, recval, reltype);
679dfad3d59SSteven Rostedt } else if (txtname && (warn_on_notrace_sect || make_nop)) {
680ffd618faSSteven Rostedt /*
681ffd618faSSteven Rostedt * This section is ignored by ftrace, but still
682ffd618faSSteven Rostedt * has mcount calls. Convert them to nops now.
683ffd618faSSteven Rostedt */
6843f1df120SMatt Helsley if (nop_mcount(relhdr, ehdr, txtname) < 0) {
6853f1df120SMatt Helsley result = -1;
6863f1df120SMatt Helsley goto out;
687c28d5077SSteven Rostedt }
688c28d5077SSteven Rostedt }
6893f1df120SMatt Helsley }
6903f1df120SMatt Helsley if (!result && mloc0 != mlocp)
6913f1df120SMatt Helsley result = append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
692c28d5077SSteven Rostedt rel_entsize, symsec_sh_link);
6933f1df120SMatt Helsley out:
694c28d5077SSteven Rostedt free(mrel0);
695c28d5077SSteven Rostedt free(mloc0);
6963f1df120SMatt Helsley return result;
697c28d5077SSteven Rostedt }
698