[compiler-rt] [compiler-rt] Fix frame numbering for unparsable frames. (PR #148278)
Jesse Schwartzentruber via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 11 12:08:31 PDT 2025
https://github.com/jschwartzentruber created https://github.com/llvm/llvm-project/pull/148278
This can happen when JIT code is run, and we can't symbolize those frames, but they should remain numbered in the stack. An example spidermonkey trace:
```
#0 0x564ac90fb80f (/builds/worker/dist/bin/js+0x240e80f) (BuildId: 5d053c76aad4cfbd08259f8832e7ac78bbeeab58)
#1 0x564ac9223a64 (/builds/worker/dist/bin/js+0x2536a64) (BuildId: 5d053c76aad4cfbd08259f8832e7ac78bbeeab58)
#2 0x564ac922316f (/builds/worker/dist/bin/js+0x253616f) (BuildId: 5d053c76aad4cfbd08259f8832e7ac78bbeeab58)
#3 0x564ac9eac032 (/builds/worker/dist/bin/js+0x31bf032) (BuildId: 5d053c76aad4cfbd08259f8832e7ac78bbeeab58)
#4 0x0dec477ca22e (<unknown module>)
```
Without this change, the following symbolization is output:
```
#0 0x55a6d72f980f in MOZ_CrashSequence /builds/worker/workspace/obj-build/dist/include/mozilla/Assertions.h:248:3
#1 0x55a6d72f980f in Crash(JSContext*, unsigned int, JS::Value*) /builds/worker/checkouts/gecko/js/src/shell/js.cpp:4223:5
#2 0x55a6d7421a64 in CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), js::CallReason, JS::CallArgs const&) /builds/worker/checkouts/gecko/js/src/vm/Interpreter.cpp:501:13
#3 0x55a6d742116f in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) /builds/worker/checkouts/gecko/js/src/vm/Interpreter.cpp:597:12
#4 0x55a6d80aa032 in js::jit::DoCallFallback(JSContext*, js::jit::BaselineFrame*, js::jit::ICFallbackStub*, unsigned int, JS::Value*, JS::MutableHandle<JS::Value>) /builds/worker/checkouts/gecko/js/src/jit/BaselineIC.cpp:1705:10
#4 0x2c803bd8f22e (<unknown module>)
```
The last frame has a duplicate number. With this change the numbering is correct:
```
#0 0x5620c58ec80f in MOZ_CrashSequence /builds/worker/workspace/obj-build/dist/include/mozilla/Assertions.h:248:3
#1 0x5620c58ec80f in Crash(JSContext*, unsigned int, JS::Value*) /builds/worker/checkouts/gecko/js/src/shell/js.cpp:4223:5
#2 0x5620c5a14a64 in CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), js::CallReason, JS::CallArgs const&) /builds/worker/checkouts/gecko/js/src/vm/Interpreter.cpp:501:13
#3 0x5620c5a1416f in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) /builds/worker/checkouts/gecko/js/src/vm/Interpreter.cpp:597:12
#4 0x5620c669d032 in js::jit::DoCallFallback(JSContext*, js::jit::BaselineFrame*, js::jit::ICFallbackStub*, unsigned int, JS::Value*, JS::MutableHandle<JS::Value>) /builds/worker/checkouts/gecko/js/src/jit/BaselineIC.cpp:1705:10
#5 0x349f24c7022e (<unknown module>)
```
>From c3e8617521ad03d7b554d68a5ab9dce6b274c2b5 Mon Sep 17 00:00:00 2001
From: Jesse Schwartzentruber <truber at mozilla.com>
Date: Fri, 11 Jul 2025 14:58:57 -0400
Subject: [PATCH] [compiler-rt] Fix frame numbering for unparsable frames.
This can happen when JIT code is run, and we can't symbolize those
frames, but they should remain numbered in the stack.
---
.../lib/asan/scripts/asan_symbolize.py | 47 ++++++++++++-------
1 file changed, 30 insertions(+), 17 deletions(-)
diff --git a/compiler-rt/lib/asan/scripts/asan_symbolize.py b/compiler-rt/lib/asan/scripts/asan_symbolize.py
index 058a1614b55e6..e70f987f03fe6 100755
--- a/compiler-rt/lib/asan/scripts/asan_symbolize.py
+++ b/compiler-rt/lib/asan/scripts/asan_symbolize.py
@@ -22,7 +22,6 @@
import argparse
import bisect
import errno
-import getopt
import logging
import os
import re
@@ -38,6 +37,7 @@
allow_system_symbolizer = True
force_system_symbolizer = False
+
# FIXME: merge the code that calls fix_filename().
def fix_filename(file_name):
if fix_filename_patterns:
@@ -507,20 +507,29 @@ def symbolize_address(self, addr, binary, offset, arch):
assert result
return result
- def get_symbolized_lines(self, symbolized_lines, inc_frame_counter=True):
+ def get_symbolized_lines(self, symbolized_lines):
if not symbolized_lines:
- if inc_frame_counter:
- self.frame_no += 1
- return [self.current_line]
- else:
- assert inc_frame_counter
- result = []
- for symbolized_frame in symbolized_lines:
- result.append(
- " #%s %s" % (str(self.frame_no), symbolized_frame.rstrip())
+ # If it is an unparsable frame, but contains a frame counter and address
+ # replace the frame counter so the stack is still consistent.
+ unknown_stack_frame_format = r"^( *#([0-9]+) +)(0x[0-9a-f]+) +.*"
+ match = re.match(unknown_stack_frame_format, self.current_line)
+ if match:
+ rewritten_line = (
+ self.current_line[: match.start(2)]
+ + str(self.frame_no)
+ + self.current_line[match.end(2) :]
)
self.frame_no += 1
- return result
+ return [rewritten_line]
+ # Not a frame line so don't increment the frame counter.
+ return [self.current_line]
+ result = []
+ for symbolized_frame in symbolized_lines:
+ result.append(
+ " #%s %s" % (str(self.frame_no), symbolized_frame.rstrip())
+ )
+ self.frame_no += 1
+ return result
def process_logfile(self):
self.frame_no = 0
@@ -546,8 +555,7 @@ def process_line_posix(self, line):
match = re.match(stack_trace_line_format, line)
if not match:
logging.debug('Line "{}" does not match regex'.format(line))
- # Not a frame line so don't increment the frame counter.
- return self.get_symbolized_lines(None, inc_frame_counter=False)
+ return self.get_symbolized_lines(None)
logging.debug(line)
_, frameno_str, addr, binary, offset = match.groups()
@@ -603,6 +611,7 @@ def _load_plugin_from_file_impl_py_gt_2(self, file_path, globals_space):
def load_plugin_from_file(self, file_path):
logging.info('Loading plugins from "{}"'.format(file_path))
globals_space = dict(globals())
+
# Provide function to register plugins
def register_plugin(plugin):
logging.info("Registering plugin %s", plugin.get_name())
@@ -779,9 +788,13 @@ def __str__(self):
arch=self.arch,
start_addr=self.start_addr,
end_addr=self.end_addr,
- module_path=self.module_path
- if self.module_path == self.module_path_for_symbolization
- else "{} ({})".format(self.module_path_for_symbolization, self.module_path),
+ module_path=(
+ self.module_path
+ if self.module_path == self.module_path_for_symbolization
+ else "{} ({})".format(
+ self.module_path_for_symbolization, self.module_path
+ )
+ ),
uuid=self.uuid,
)
More information about the llvm-commits
mailing list