-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
142 lines (114 loc) · 4.16 KB
/
index.js
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
'use strict';
var prettyTrace = require('pretty-trace');
var instrumentsCsvRegex = prettyTrace.regexes.instruments.csv.regex;
var hexAddressRegex = /0x([0-9A-Fa-f]{2,12})/
, lldb_backtraceRegex = /(:?0x(?:(?:\d|[abcdefABCDEF]){0,2})+) +in +(:?0x(?:(?:\d|[abcdefABCDEF]){0,2})+)/
// TODO: faster IMO, not working currently ATM
// , lldb_backtraceRegex = /0x[0-9A-Fa-f]{2,12} +in 0x[0-9A-Fa-f]{2,12}/
function byDecimalAddress(a, b) {
return a.decimalAddress < b.decimalAddress ? -1 : 1;
}
function processLine(acc, x) {
if (!x.trim().length) return acc;
var parts = x.split(/ +/);
if (parts.length < 3) return acc;
var decimal = parseInt(parts[0], 16)
var item = {
address : parts[0]
, size : parts[1]
, decimalAddress : decimal
, symbol : parts.slice(2).join(' ') }
acc.push(item);
return acc;
}
/**
* Instantiates a JIT resolver for the given map.
*
* @name JITResolver
* @function
* @param {String|Array.<String>} map either a string or lines with space separated HexAddress, Size, Symbol on each line
* @return {Object} the initialized JIT resolver
*/
function JITResolver(map) {
if (!(this instanceof JITResolver)) return new JITResolver(map);
var lines = Array.isArray(map) ? map : map.split('\n')
this._addresses = lines
.reduce(processLine, [])
.sort(byDecimalAddress)
this._len = this._addresses.length;
}
module.exports = JITResolver;
var proto = JITResolver.prototype;
/**
* Matches the address of the symbol of which the given address is part of.
*
*
* @name JITResolver::resolve
* @function
* @param {String|Number} hexAddress the hexadecimal address of the address to check
* @return {Object} info of the matching symbol which includes address, size, symbol
*/
proto.resolve = function resolve(hexAddress) {
var match = null;
var a = typeof hexAddress === 'number' ? hexAddress : parseInt(hexAddress, 16);
for (var i = 0; i < this._len; i++) {
// once we hit a larger address that means our symbol/function that this
// address is part of starts at the previous address
if(a < this._addresses[i].decimalAddress) {
match = this._addresses[i - 1];
break;
}
}
return match;
}
function defaultGetHexAddress(line) {
var m = line.match(hexAddressRegex);
if (!m) return null;
var matchStackTrace = line.match(lldb_backtraceRegex);
var res;
if (matchStackTrace) {
// lldb backtrace
return { address: matchStackTrace[2], include: false }
}
var include = !instrumentsCsvRegex.test(line);
return m && { address: m[0], include: include }
}
/**
* Resolves all symbols in a given stack and replaces them accordingly
*
* @name JITResolver::resolveMulti
* @function
* @param {Array.<String>|String} stack string of stack or lines of stack
* @param {function=} getHexAddress allows overriding the function used to find a hex address on each line, returns `{ address: 0x000, include: true|false }`
* @return {Array.<String>|String} the stack with symbols resolved in the same format that the stack was given, either as lines or one string
*/
proto.resolveMulti = function resolveMulti(stack, getHexAddress) {
getHexAddress = getHexAddress || defaultGetHexAddress;
var self = this;
var isLines = Array.isArray(stack)
var lines = isLines ? stack : stack.split('\n')
function processLine(line) {
var replacement;
var match = getHexAddress(line);
if (!match || !match.address) return line;
var resolved = self.resolve(match.address);
if (!resolved) return line;
return line.replace(match.address, match.include ? match.address + ' ' + resolved.symbol : resolved.symbol);
}
var processedLines = lines.map(processLine);
return isLines ? processedLines : processedLines.join('\n');
}
/**
* RegExp used to match memory addresses.
*
* @name JITResolver::hexAddressRegex
*/
proto.hexAddressRegex = hexAddressRegex;
/**
* RegExp used to match memory lldb backtraces of the form `#1 0x001 in 0x001 ()`
* When calling `var m = s.match(regex)`
* `m[1]` contains first matched address and `m[2]` contains second matched address.
*
* @name JITResolver::lldb_backtraceRegex
*/
proto.lldb_backtraceRegex = lldb_backtraceRegex;