History

kallsyms: strip LTO suffixes from static functions

Similar to: commit 8b8e6b5d3b01 ("kallsyms: strip ThinLTO hashes from static functions") It's very common for compilers to modify the symbol name for static functions as part of optimizing transformations. That makes hooking static functions (that weren't inlined or DCE'd) with kprobes difficult. LLVM has yet another name mangling scheme used by thin LTO. Combine handling of the various schemes by truncating after the first '.'. Strip off these suffixes so that we can continue to hook such static functions. Clang releases prior to clang-13 would use '$' instead of '.'

Nick Desaulniers committed 5 years ago

Commit 6eb4bd91 parent 4c78c721 file · +33 −13Browse files

Unified · Split

kernel/kallsyms.c+33−13
@@ -164,26 +164,46 @@ static unsigned long kallsyms_sym_address(int idx) · 163 unmodified lines
164 return kallsyms_relative_base - 1 - kallsyms_offsets[idx];164 return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
165}165}
166 166
167#if defined(CONFIG_CFI_CLANG) && defined(CONFIG_LTO_CLANG_THIN)167static bool cleanup_symbol_name(char *s)
168/*
169 * LLVM appends a hash to static function names when ThinLTO and CFI are
170 * both enabled, i.e. foo() becomes foo$707af9a22804d33c81801f27dcfe489b.
171 * This causes confusion and potentially breaks user space tools, so we
172 * strip the suffix from expanded symbol names.
173 */
174static inline bool cleanup_symbol_name(char *s)
175{168{
176 char *res;169 char *res;
177 170
171 if (!IS_ENABLED(CONFIG_LTO_CLANG))
172 return false;
173
174 /*
175 * LLVM appends various suffixes for local functions and variables that
176 * must be promoted to global scope as part of LTO. This can break
177 * hooking of static functions with kprobes. '.' is not a valid
178 * character in an identifier in C. Suffixes observed:
179 * - foo.llvm.[0-9a-f]+
180 * - foo.[0-9a-f]+
181 * - foo.[0-9a-f]+.cfi_jt
182 */
183 res = strchr(s, '.');
184 if (res) {
185 *res = '\0';
186 return true;
187 }
188
189 if (!IS_ENABLED(CONFIG_CFI_CLANG) ||
190 !IS_ENABLED(CONFIG_LTO_CLANG_THIN) ||
191 CONFIG_CLANG_VERSION >= 130000)
192 return false;
193
194 /*
195 * Prior to LLVM 13, the following suffixes were observed when thinLTO
196 * and CFI are both enabled:
197 * - foo$[0-9]+
198 */
178 res = strrchr(s, '$');199 res = strrchr(s, '$');
179 if (res)200 if (res) {
180 *res = '\0';201 *res = '\0';
202 return true;
203 }
181 204
182 return res != NULL;205 return false;
183}206}
184#else
185static inline bool cleanup_symbol_name(char *s) { return false; }
186#endif
187 207
188/* Lookup the address for this symbol. Returns 0 if not found. */208/* Lookup the address for this symbol. Returns 0 if not found. */
189unsigned long kallsyms_lookup_name(const char *name)209unsigned long kallsyms_lookup_name(const char *name)