summaryrefslogtreecommitdiffstats
path: root/tools/profiler/rust-helper/src/lib.rs
blob: a22e6318525c1207db965f695015a84e11c5c18b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate memmap;
extern crate rustc_demangle;
extern crate thin_vec;
extern crate uuid;

#[cfg(feature = "parse_elf")]
extern crate goblin;
#[cfg(feature = "parse_elf")]
extern crate object;

mod compact_symbol_table;

#[cfg(feature = "parse_elf")]
mod elf;

#[cfg(feature = "parse_elf")]
use memmap::MmapOptions;
#[cfg(feature = "parse_elf")]
use std::fs::File;

use compact_symbol_table::CompactSymbolTable;
use rustc_demangle::try_demangle;
use std::ffi::CStr;
use std::mem;
use std::os::raw::c_char;
use std::ptr;

#[cfg(feature = "parse_elf")]
pub fn get_compact_symbol_table_from_file(
    debug_path: &str,
    breakpad_id: Option<&str>,
) -> Option<CompactSymbolTable> {
    let file = File::open(debug_path).ok()?;
    let buffer = unsafe { MmapOptions::new().map(&file).ok()? };
    elf::get_compact_symbol_table(&buffer, breakpad_id)
}

#[cfg(not(feature = "parse_elf"))]
pub fn get_compact_symbol_table_from_file(
    _debug_path: &str,
    _breakpad_id: Option<&str>,
) -> Option<CompactSymbolTable> {
    None
}

#[no_mangle]
pub extern "C" fn profiler_get_symbol_table(
    debug_path: *const c_char,
    breakpad_id: *const c_char,
    symbol_table: &mut CompactSymbolTable,
) -> bool {
    let debug_path = unsafe { CStr::from_ptr(debug_path).to_string_lossy() };
    let breakpad_id = if breakpad_id.is_null() {
        None
    } else {
        match unsafe { CStr::from_ptr(breakpad_id).to_str() } {
            Ok(s) => Some(s),
            Err(_) => return false,
        }
    };

    match get_compact_symbol_table_from_file(&debug_path, breakpad_id.map(|id| id.as_ref())) {
        Some(mut st) => {
            std::mem::swap(symbol_table, &mut st);
            true
        }
        None => false,
    }
}

#[no_mangle]
pub extern "C" fn profiler_demangle_rust(
    mangled: *const c_char,
    buffer: *mut c_char,
    buffer_len: usize,
) -> bool {
    assert!(!mangled.is_null());
    assert!(!buffer.is_null());

    if buffer_len == 0 {
        return false;
    }

    let buffer: *mut u8 = unsafe { mem::transmute(buffer) };
    let mangled = match unsafe { CStr::from_ptr(mangled).to_str() } {
        Ok(s) => s,
        Err(_) => return false,
    };

    match try_demangle(mangled) {
        Ok(demangled) => {
            let mut demangled = format!("{:#}", demangled);
            if !demangled.is_ascii() {
                return false;
            }
            demangled.truncate(buffer_len - 1);

            let bytes = demangled.as_bytes();
            unsafe {
                ptr::copy(bytes.as_ptr(), buffer, bytes.len());
                ptr::write(buffer.offset(bytes.len() as isize), 0);
            }
            true
        }
        Err(_) => false,
    }
}