@@ -60,6 +60,104 @@ static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn)
6060 return NULL ;
6161}
6262
63+ struct elf_sym {
64+ const char * name ;
65+ GElf_Sym sym ;
66+ GElf_Shdr sh ;
67+ };
68+
69+ struct elf_sym_iter {
70+ Elf * elf ;
71+ Elf_Data * syms ;
72+ size_t nr_syms ;
73+ size_t strtabidx ;
74+ size_t next_sym_idx ;
75+ struct elf_sym sym ;
76+ int st_type ;
77+ };
78+
79+ static int elf_sym_iter_new (struct elf_sym_iter * iter ,
80+ Elf * elf , const char * binary_path ,
81+ int sh_type , int st_type )
82+ {
83+ Elf_Scn * scn = NULL ;
84+ GElf_Ehdr ehdr ;
85+ GElf_Shdr sh ;
86+
87+ memset (iter , 0 , sizeof (* iter ));
88+
89+ if (!gelf_getehdr (elf , & ehdr )) {
90+ pr_warn ("elf: failed to get ehdr from %s: %s\n" , binary_path , elf_errmsg (-1 ));
91+ return - EINVAL ;
92+ }
93+
94+ scn = elf_find_next_scn_by_type (elf , sh_type , NULL );
95+ if (!scn ) {
96+ pr_debug ("elf: failed to find symbol table ELF sections in '%s'\n" ,
97+ binary_path );
98+ return - ENOENT ;
99+ }
100+
101+ if (!gelf_getshdr (scn , & sh ))
102+ return - EINVAL ;
103+
104+ iter -> strtabidx = sh .sh_link ;
105+ iter -> syms = elf_getdata (scn , 0 );
106+ if (!iter -> syms ) {
107+ pr_warn ("elf: failed to get symbols for symtab section in '%s': %s\n" ,
108+ binary_path , elf_errmsg (-1 ));
109+ return - EINVAL ;
110+ }
111+ iter -> nr_syms = iter -> syms -> d_size / sh .sh_entsize ;
112+ iter -> elf = elf ;
113+ iter -> st_type = st_type ;
114+ return 0 ;
115+ }
116+
117+ static struct elf_sym * elf_sym_iter_next (struct elf_sym_iter * iter )
118+ {
119+ struct elf_sym * ret = & iter -> sym ;
120+ GElf_Sym * sym = & ret -> sym ;
121+ const char * name = NULL ;
122+ Elf_Scn * sym_scn ;
123+ size_t idx ;
124+
125+ for (idx = iter -> next_sym_idx ; idx < iter -> nr_syms ; idx ++ ) {
126+ if (!gelf_getsym (iter -> syms , idx , sym ))
127+ continue ;
128+ if (GELF_ST_TYPE (sym -> st_info ) != iter -> st_type )
129+ continue ;
130+ name = elf_strptr (iter -> elf , iter -> strtabidx , sym -> st_name );
131+ if (!name )
132+ continue ;
133+ sym_scn = elf_getscn (iter -> elf , sym -> st_shndx );
134+ if (!sym_scn )
135+ continue ;
136+ if (!gelf_getshdr (sym_scn , & ret -> sh ))
137+ continue ;
138+
139+ iter -> next_sym_idx = idx + 1 ;
140+ ret -> name = name ;
141+ return ret ;
142+ }
143+
144+ return NULL ;
145+ }
146+
147+
148+ /* Transform symbol's virtual address (absolute for binaries and relative
149+ * for shared libs) into file offset, which is what kernel is expecting
150+ * for uprobe/uretprobe attachment.
151+ * See Documentation/trace/uprobetracer.rst for more details. This is done
152+ * by looking up symbol's containing section's header and using iter's virtual
153+ * address (sh_addr) and corresponding file offset (sh_offset) to transform
154+ * sym.st_value (virtual address) into desired final file offset.
155+ */
156+ static unsigned long elf_sym_offset (struct elf_sym * sym )
157+ {
158+ return sym -> sym .st_value - sym -> sh .sh_addr + sym -> sh .sh_offset ;
159+ }
160+
63161/* Find offset of function name in the provided ELF object. "binary_path" is
64162 * the path to the ELF binary represented by "elf", and only used for error
65163 * reporting matters. "name" matches symbol name or name@@LIB for library
@@ -91,94 +189,47 @@ long elf_find_func_offset(Elf *elf, const char *binary_path, const char *name)
91189 * reported as a warning/error.
92190 */
93191 for (i = 0 ; i < ARRAY_SIZE (sh_types ); i ++ ) {
94- size_t nr_syms , strtabidx , idx ;
95- Elf_Data * symbols = NULL ;
96- Elf_Scn * scn = NULL ;
192+ struct elf_sym_iter iter ;
193+ struct elf_sym * sym ;
97194 int last_bind = -1 ;
98- const char * sname ;
99- GElf_Shdr sh ;
195+ int cur_bind ;
100196
101- scn = elf_find_next_scn_by_type (elf , sh_types [i ], NULL );
102- if (!scn ) {
103- pr_debug ("elf: failed to find symbol table ELF sections in '%s'\n" ,
104- binary_path );
197+ ret = elf_sym_iter_new (& iter , elf , binary_path , sh_types [i ], STT_FUNC );
198+ if (ret == - ENOENT )
105199 continue ;
106- }
107- if (!gelf_getshdr (scn , & sh ))
108- continue ;
109- strtabidx = sh .sh_link ;
110- symbols = elf_getdata (scn , 0 );
111- if (!symbols ) {
112- pr_warn ("elf: failed to get symbols for symtab section in '%s': %s\n" ,
113- binary_path , elf_errmsg (-1 ));
114- ret = - LIBBPF_ERRNO__FORMAT ;
200+ if (ret )
115201 goto out ;
116- }
117- nr_syms = symbols -> d_size / sh .sh_entsize ;
118-
119- for (idx = 0 ; idx < nr_syms ; idx ++ ) {
120- int curr_bind ;
121- GElf_Sym sym ;
122- Elf_Scn * sym_scn ;
123- GElf_Shdr sym_sh ;
124-
125- if (!gelf_getsym (symbols , idx , & sym ))
126- continue ;
127-
128- if (GELF_ST_TYPE (sym .st_info ) != STT_FUNC )
129- continue ;
130-
131- sname = elf_strptr (elf , strtabidx , sym .st_name );
132- if (!sname )
133- continue ;
134-
135- curr_bind = GELF_ST_BIND (sym .st_info );
136202
203+ while ((sym = elf_sym_iter_next (& iter ))) {
137204 /* User can specify func, func@@LIB or func@@LIB_VERSION. */
138- if (strncmp (sname , name , name_len ) != 0 )
205+ if (strncmp (sym -> name , name , name_len ) != 0 )
139206 continue ;
140207 /* ...but we don't want a search for "foo" to match 'foo2" also, so any
141208 * additional characters in sname should be of the form "@@LIB".
142209 */
143- if (!is_name_qualified && sname [name_len ] != '\0' && sname [name_len ] != '@' )
210+ if (!is_name_qualified && sym -> name [name_len ] != '\0' && sym -> name [name_len ] != '@' )
144211 continue ;
145212
146- if (ret >= 0 ) {
213+ cur_bind = GELF_ST_BIND (sym -> sym .st_info );
214+
215+ if (ret > 0 ) {
147216 /* handle multiple matches */
148- if (last_bind != STB_WEAK && curr_bind != STB_WEAK ) {
217+ if (last_bind != STB_WEAK && cur_bind != STB_WEAK ) {
149218 /* Only accept one non-weak bind. */
150219 pr_warn ("elf: ambiguous match for '%s', '%s' in '%s'\n" ,
151- sname , name , binary_path );
220+ sym -> name , name , binary_path );
152221 ret = - LIBBPF_ERRNO__FORMAT ;
153222 goto out ;
154- } else if (curr_bind == STB_WEAK ) {
223+ } else if (cur_bind == STB_WEAK ) {
155224 /* already have a non-weak bind, and
156225 * this is a weak bind, so ignore.
157226 */
158227 continue ;
159228 }
160229 }
161230
162- /* Transform symbol's virtual address (absolute for
163- * binaries and relative for shared libs) into file
164- * offset, which is what kernel is expecting for
165- * uprobe/uretprobe attachment.
166- * See Documentation/trace/uprobetracer.rst for more
167- * details.
168- * This is done by looking up symbol's containing
169- * section's header and using it's virtual address
170- * (sh_addr) and corresponding file offset (sh_offset)
171- * to transform sym.st_value (virtual address) into
172- * desired final file offset.
173- */
174- sym_scn = elf_getscn (elf , sym .st_shndx );
175- if (!sym_scn )
176- continue ;
177- if (!gelf_getshdr (sym_scn , & sym_sh ))
178- continue ;
179-
180- ret = sym .st_value - sym_sh .sh_addr + sym_sh .sh_offset ;
181- last_bind = curr_bind ;
231+ ret = elf_sym_offset (sym );
232+ last_bind = cur_bind ;
182233 }
183234 if (ret > 0 )
184235 break ;
0 commit comments