mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
9fc18106c8
## Summary `profiler-stack-query` Android stacks come straight from perf, which stores frame names **mangled** — so `function_callers` / `hang_stacks` output reads like: ``` _ZN16GrDrawingManager5flushE6SkSpan... <- _ZL25libutil_thread_trampolinePv.__uniq.2265... <- __start_thread ``` This adds a conservative, best-effort Itanium demangler and applies it when rendering those stacks (display-only — SQL matching upstream still uses the raw mangled names). The same stack now reads: ``` GrDrawingManager::flush <- libutil_thread_trampoline <- __start_thread ``` ## What it handles - Nested names (`_ZN...E`) and plain function names; the argument list is dropped. - Strips LLVM/GCC internal suffixes (`.__uniq.*`, `.llvm.*`, `.part.*`, `.cold`). - **Conservative:** templates, substitutions, and kernel C symbols it can't confidently parse are returned **verbatim** — it never corrupts a name. ## Test plan - New `test/android-perfetto/demangle.test.ts` (10 cases incl. fallbacks). - Updated `function-callers.test.ts` to expect the demangled leaf in the substring-match note. - `npm test -w @argent/tool-server` — all pass; build + `typecheck:tests` clean. > Part of a set of native-profiler fixes. Note: this and #338 both touch the `hang_stacks` sample renderer — whichever merges second needs a trivial rebase.
66 lines
2.6 KiB
TypeScript
66 lines
2.6 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { demangleSymbol, demangleCallstackText } from "../../src/utils/profiler-shared/demangle";
|
|
|
|
describe("demangleSymbol", () => {
|
|
it("demangles a nested name and drops the argument list", () => {
|
|
// _ZN16GrDrawingManager5flushE6SkSpan... → GrDrawingManager::flush
|
|
expect(demangleSymbol("_ZN16GrDrawingManager5flushE6SkSpanIP14GrSurfaceProxyE")).toBe(
|
|
"GrDrawingManager::flush"
|
|
);
|
|
});
|
|
|
|
it("demangles a plain (non-nested) function name", () => {
|
|
expect(demangleSymbol("_Z13uncompressLZWP7_JNIEnv")).toBe("uncompressLZW");
|
|
expect(demangleSymbol("_Z23__pthread_internal_findlPKc")).toBe("__pthread_internal_find");
|
|
});
|
|
|
|
it("handles internal-linkage (_ZL) symbols", () => {
|
|
expect(demangleSymbol("_ZL25libutil_thread_trampolinePv")).toBe("libutil_thread_trampoline");
|
|
});
|
|
|
|
it("strips LLVM internal suffixes", () => {
|
|
expect(
|
|
demangleSymbol(
|
|
"_ZL25libutil_thread_trampolinePv.__uniq.226528677032898775202282855395389835431"
|
|
)
|
|
).toBe("libutil_thread_trampoline");
|
|
});
|
|
|
|
it("maps the std abbreviation in a parseable nested name", () => {
|
|
// _ZNSt6chrono5stealE → std::chrono::steal
|
|
expect(demangleSymbol("_ZNSt6chrono5stealE")).toBe("std::chrono::steal");
|
|
});
|
|
|
|
it("bails to the raw name on templates rather than guessing", () => {
|
|
// Template args (`I...E`) are out of scope: returning the raw mangled name
|
|
// is safer than emitting a partial, misleading demangle.
|
|
expect(demangleSymbol("_ZNSt6vectorIiE9push_backEi")).toBe("_ZNSt6vectorIiE9push_backEi");
|
|
});
|
|
|
|
it("returns plain C / kernel symbols unchanged", () => {
|
|
expect(demangleSymbol("goldfish_pipe_read_write")).toBe("goldfish_pipe_read_write");
|
|
expect(demangleSymbol("do_syscall_64")).toBe("do_syscall_64");
|
|
expect(demangleSymbol("__start_thread")).toBe("__start_thread");
|
|
});
|
|
|
|
it("never corrupts an unparseable mangled name (returns it raw)", () => {
|
|
expect(demangleSymbol("_ZWeird$$$NotReal")).toBe("_ZWeird$$$NotReal");
|
|
expect(demangleSymbol("")).toBe("");
|
|
});
|
|
});
|
|
|
|
describe("demangleCallstackText", () => {
|
|
it("demangles each frame and preserves the ' <- ' separators and order", () => {
|
|
const raw =
|
|
"_ZN16GrDrawingManager5flushE6SkSpan <- _ZL25libutil_thread_trampolinePv <- __start_thread";
|
|
expect(demangleCallstackText(raw)).toBe(
|
|
"GrDrawingManager::flush <- libutil_thread_trampoline <- __start_thread"
|
|
);
|
|
});
|
|
|
|
it("leaves an all-C kernel stack readable and unchanged", () => {
|
|
const raw = "goldfish_pipe_read_write <- vfs_read <- do_syscall_64";
|
|
expect(demangleCallstackText(raw)).toBe(raw);
|
|
});
|
|
});
|