Skip to content

Commit

Permalink
Use wasm to demangle C++ and Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
cerisier committed Jan 11, 2025
1 parent 9560a1b commit 5f7f56e
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 54 deletions.
13 changes: 0 additions & 13 deletions src/lib/demangle-cpp.test.ts

This file was deleted.

32 changes: 0 additions & 32 deletions src/lib/demangle-cpp.ts

This file was deleted.

23 changes: 23 additions & 0 deletions src/lib/demangle.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {loadDemangling} from './demangle'

test('demangle', async () => {
const demangle = await loadDemangling()

expect(demangle('a')).toBe('a')
expect(demangle('someUnobfuscatedFunction')).toBe('someUnobfuscatedFunction')

// C++ mangling
expect(demangle('__ZNK7Support6ColorFeqERKS0_')).toBe(
'Support::ColorF::operator==(Support::ColorF const&) const',
)
// Running a second time to test the cache
expect(demangle('__ZNK7Support6ColorFeqERKS0_')).toBe(
'Support::ColorF::operator==(Support::ColorF const&) const',
)

// Rust v0 mangling
expect(demangle('_RNvCskwGfYPst2Cb_3foo16example_function')).toBe('foo::example_function')

// Rust legacy mangling
expect(demangle('_ZN3std2fs8Metadata7created17h8df207f105c5d474E')).toBe('std::fs::Metadata::created::h8df207f105c5d474')

Check failure on line 22 in src/lib/demangle.test.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Replace `'std::fs::Metadata::created::h8df207f105c5d474'` with `⏎····'std::fs::Metadata::created::h8df207f105c5d474',⏎··`

Check failure on line 22 in src/lib/demangle.test.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Replace `'std::fs::Metadata::created::h8df207f105c5d474'` with `⏎····'std::fs::Metadata::created::h8df207f105c5d474',⏎··`
})
25 changes: 25 additions & 0 deletions src/lib/demangle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import createWasmDemangleModule from "./demangle.wasm";

Check failure on line 1 in src/lib/demangle.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Replace `"./demangle.wasm";` with `'./demangle.wasm'`

Check failure on line 1 in src/lib/demangle.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Replace `"./demangle.wasm";` with `'./demangle.wasm'`

const cache = new Map<string, string>()

export async function loadDemangling(): Promise<(name: string) => string> {
// This function converts a mangled C++ name such as "__ZNK7Support6ColorFeqERKS0_"
// into a human-readable symbol (in this case "Support::ColorF::==(Support::ColorF&)")
const wasmDemangleModule = await createWasmDemangleModule();

Check failure on line 8 in src/lib/demangle.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Delete `;`

Check failure on line 8 in src/lib/demangle.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Delete `;`
return cached(wasmDemangleModule.wasm_demangle);

Check failure on line 9 in src/lib/demangle.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Delete `;`

Check failure on line 9 in src/lib/demangle.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Delete `;`
}

function cached(demangle: (name: string) => string): (name: string) => string {
return (name: string): string => {
let result = cache.get(name)
if (result !== undefined) {
name = result
} else {
result = demangle(name)
result = result === '' ? name : result
cache.set(name, result)
name = result
}
return name
}
}
5 changes: 5 additions & 0 deletions src/lib/demangle.wasm.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
interface WasmDemangleModule {
wasm_demangle(mangled: string): string

Check failure on line 2 in src/lib/demangle.wasm.d.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Delete `··`

Check failure on line 2 in src/lib/demangle.wasm.d.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Delete `··`
}

export default function ModuleFactory(options?: unknown): Promise<WasmDemangleModule>;

Check failure on line 5 in src/lib/demangle.wasm.d.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Delete `;`

Check failure on line 5 in src/lib/demangle.wasm.d.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Delete `;`
22 changes: 22 additions & 0 deletions src/lib/demangle.wasm.js

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions src/lib/profile.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {lastOf, KeyedSet} from './utils'
import {ValueFormatter, RawValueFormatter} from './value-formatters'
import {FileFormat} from './file-format-spec'
const demangleCppModule = import('./demangle-cpp')

export interface FrameInfo {
key: string | number
Expand Down Expand Up @@ -404,16 +403,16 @@ export class Profile {

// Demangle symbols for readability
async demangle() {
let demangleCpp: ((name: string) => string) | null = null
let demangle: ((name: string) => string) | null = null

for (let frame of this.frames) {
// This function converts a mangled C++ name such as "__ZNK7Support6ColorFeqERKS0_"
// into a human-readable symbol (in this case "Support::ColorF::==(Support::ColorF&)")
if (frame.name.startsWith('__Z')) {
if (!demangleCpp) {
demangleCpp = (await demangleCppModule).demangleCpp
// This function converts a mangled C++ and Rust name into a human-readable symbol.
if (frame.name.startsWith('__Z') || frame.name.startsWith('_R') || frame.name.startsWith('_Z')) {

Check failure on line 410 in src/lib/profile.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

Replace `frame.name.startsWith('__Z')·||·frame.name.startsWith('_R')·||·frame.name.startsWith('_Z')` with `⏎········frame.name.startsWith('__Z')·||⏎········frame.name.startsWith('_R')·||⏎········frame.name.startsWith('_Z')⏎······`

Check failure on line 410 in src/lib/profile.ts

View workflow job for this annotation

GitHub Actions / test (20.x)

Replace `frame.name.startsWith('__Z')·||·frame.name.startsWith('_R')·||·frame.name.startsWith('_Z')` with `⏎········frame.name.startsWith('__Z')·||⏎········frame.name.startsWith('_R')·||⏎········frame.name.startsWith('_Z')⏎······`
if (!demangle) {
const demangleModule = await import('./demangle')
demangle = await demangleModule.loadDemangling()
}
frame.name = demangleCpp(frame.name)
frame.name = demangle(frame.name)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/views/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const importModule = import('../import')
// We put them all in one place so we can directly control the relative priority
// of these.
importModule.then(() => {})
import('../lib/demangle-cpp').then(() => {})
import('../lib/demangle').then(() => {})
import('source-map').then(() => {})

async function importProfilesFromText(
Expand Down

0 comments on commit 5f7f56e

Please sign in to comment.