Symbolication.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @flow
  8. * @format
  9. */
  10. 'use strict';
  11. const SourceMetadataMapConsumer = require('./SourceMetadataMapConsumer');
  12. const fs = require('fs');
  13. const invariant = require('invariant');
  14. const path = require('path');
  15. import type {MixedSourceMap, HermesFunctionOffsets} from 'metro-source-map';
  16. // flowlint-next-line untyped-type-import:off
  17. import {typeof SourceMapConsumer} from 'source-map';
  18. type SingleMapModuleIds = {
  19. segmentId: number,
  20. localId: ?number,
  21. ...
  22. };
  23. type ContextOptionsInput = {
  24. +nameSource?: 'function_names' | 'identifier_names',
  25. +inputLineStart?: number,
  26. +inputColumnStart?: number,
  27. +outputLineStart?: number,
  28. +outputColumnStart?: number,
  29. ...
  30. };
  31. // TODO (T46584006): Write the real types for these.
  32. // eslint-disable-next-line lint/no-unclear-flowtypes
  33. type SizeAttributionMap = Object;
  34. // eslint-disable-next-line lint/no-unclear-flowtypes
  35. type ChromeTrace = Object;
  36. // eslint-disable-next-line lint/no-unclear-flowtypes
  37. type ChromeTraceEntry = Object;
  38. type HermesMinidumpCrashInfo = {
  39. +callstack: $ReadOnlyArray<HermesMinidumpStackFrame | NativeCodeStackFrame>,
  40. ...
  41. };
  42. type HermesMinidumpStackFrame = $ReadOnly<{|
  43. ByteCodeOffset: number,
  44. FunctionID: number,
  45. CJSModuleOffset: number,
  46. SourceURL: string,
  47. StackFrameRegOffs: string,
  48. SourceLocation?: string,
  49. |}>;
  50. type NativeCodeStackFrame = $ReadOnly<{|
  51. NativeCode: true,
  52. StackFrameRegOffs: string,
  53. |}>;
  54. type SymbolicatedStackTrace = $ReadOnlyArray<
  55. SymbolicatedStackFrame | NativeCodeStackFrame,
  56. >;
  57. type SymbolicatedStackFrame = $ReadOnly<{|
  58. line: ?number,
  59. column: ?number,
  60. source: ?string,
  61. functionName: ?string,
  62. name: ?string,
  63. |}>;
  64. const UNKNOWN_MODULE_IDS: SingleMapModuleIds = {
  65. segmentId: 0,
  66. localId: undefined,
  67. };
  68. class SymbolicationContext<ModuleIdsT> {
  69. +options: {
  70. +nameSource: 'function_names' | 'identifier_names',
  71. +inputLineStart: number,
  72. +inputColumnStart: number,
  73. +outputLineStart: number,
  74. +outputColumnStart: number,
  75. ...
  76. };
  77. constructor(options: ContextOptionsInput) {
  78. this.options = {
  79. inputLineStart: 1,
  80. inputColumnStart: 0,
  81. outputLineStart: 1,
  82. outputColumnStart: 0,
  83. nameSource: 'function_names',
  84. };
  85. if (options) {
  86. for (const option of [
  87. 'inputLineStart',
  88. 'inputColumnStart',
  89. 'outputLineStart',
  90. 'outputColumnStart',
  91. ]) {
  92. if (options[option] != null) {
  93. this.options[option] = options[option];
  94. }
  95. }
  96. if (options.nameSource != null) {
  97. this.options.nameSource = options.nameSource;
  98. }
  99. }
  100. }
  101. // parse stack trace with String.replace
  102. // replace the matched part of stack trace to symbolicated result
  103. // sample stack trace:
  104. // IOS: foo@4:18131, Android: bar:4:18063
  105. // sample stack trace with module id:
  106. // IOS: foo@123.js:4:18131, Android: bar:123.js:4:18063
  107. // sample stack trace without function name:
  108. // 123.js:4:18131
  109. // sample result:
  110. // IOS: foo.js:57:foo, Android: bar.js:75:bar
  111. symbolicate(stackTrace: string): string {
  112. return stackTrace.replace(
  113. /(?:([^@: \n(]+)(@|:))?(?:(?:([^@: \n(]+):)?(\d+):(\d+)|\[native code\])/g,
  114. (match, func, delimiter, fileName, line, column) => {
  115. if (delimiter === ':' && func && !fileName) {
  116. fileName = func;
  117. func = null;
  118. }
  119. const original = this.getOriginalPositionFor(
  120. line,
  121. column,
  122. this.parseFileName(fileName || ''),
  123. );
  124. return (
  125. (original.source ?? 'null') +
  126. ':' +
  127. (original.line ?? 'null') +
  128. ':' +
  129. (original.name ?? 'null')
  130. );
  131. },
  132. );
  133. }
  134. // Taking in a map like
  135. // trampoline offset (optional js function name)
  136. // JS_0158_xxxxxxxxxxxxxxxxxxxxxx fe 91081
  137. // JS_0159_xxxxxxxxxxxxxxxxxxxxxx Ft 68651
  138. // JS_0160_xxxxxxxxxxxxxxxxxxxxxx value 50700
  139. // JS_0161_xxxxxxxxxxxxxxxxxxxxxx setGapAtCursor 0
  140. // JS_0162_xxxxxxxxxxxxxxxxxxxxxx (unknown) 50818
  141. // JS_0163_xxxxxxxxxxxxxxxxxxxxxx value 108267
  142. symbolicateProfilerMap(mapFile: string): string {
  143. return fs
  144. .readFileSync(mapFile, 'utf8')
  145. .split('\n')
  146. .slice(0, -1)
  147. .map(line => {
  148. const line_list = line.split(' ');
  149. const trampoline = line_list[0];
  150. const js_name = line_list[1];
  151. const offset = parseInt(line_list[2], 10);
  152. if (!offset) {
  153. return trampoline + ' ' + trampoline;
  154. }
  155. const original = this.getOriginalPositionFor(
  156. this.options.inputLineStart,
  157. offset,
  158. );
  159. return (
  160. trampoline +
  161. ' ' +
  162. (original.name || js_name) +
  163. '::' +
  164. [original.source, original.line, original.column].join(':')
  165. );
  166. })
  167. .join('\n');
  168. }
  169. symbolicateAttribution(obj: SizeAttributionMap): SizeAttributionMap {
  170. const loc = obj.location;
  171. const line = loc.line != null ? loc.line : this.options.inputLineStart;
  172. let column = loc.column != null ? loc.column : loc.virtualOffset;
  173. const file = loc.filename ? this.parseFileName(loc.filename) : null;
  174. let original = this.getOriginalPositionFor(line, column, file);
  175. const isBytecodeRange =
  176. loc.bytecodeSize != null &&
  177. loc.virtualOffset != null &&
  178. !loc.column != null;
  179. // Functions compiled from Metro-bundled modules will often have a little bit
  180. // of unmapped wrapper code right at the beginning - which is where we query.
  181. // Let's attribute them to where the inner module code originates instead.
  182. // This loop is O(n*log(n)) in the size of the function, but we will generally
  183. // either:
  184. // 1. Find a non-null mapping within one or two iterations; or
  185. // 2. Reach the end of the function without encountering mappings - this might
  186. // happen for function bodies that never throw (generally very short).
  187. while (
  188. isBytecodeRange &&
  189. original.source == null &&
  190. ++column < loc.virtualOffset + loc.bytecodeSize
  191. ) {
  192. original = this.getOriginalPositionFor(line, column, file);
  193. }
  194. obj.location = {
  195. file: original.source,
  196. line: original.line,
  197. column: original.column,
  198. };
  199. }
  200. // Symbolicate chrome trace "stackFrames" section.
  201. // Each frame in it has three fields: name, funcVirtAddr(optional), offset(optional).
  202. // funcVirtAddr and offset are only available if trace is generated from
  203. // hbc bundle without debug info.
  204. symbolicateChromeTrace(
  205. traceFile: string,
  206. {
  207. stdout,
  208. stderr,
  209. }: {
  210. stdout: stream$Writable,
  211. stderr: stream$Writable,
  212. ...
  213. },
  214. ): void {
  215. const contentJson: ChromeTrace = JSON.parse(
  216. fs.readFileSync(traceFile, 'utf8'),
  217. );
  218. if (contentJson.stackFrames == null) {
  219. throw new Error('Unable to locate `stackFrames` section in trace.');
  220. }
  221. stdout.write(
  222. 'Processing ' + Object.keys(contentJson.stackFrames).length + ' frames\n',
  223. );
  224. Object.values(contentJson.stackFrames).forEach(
  225. (entry: ChromeTraceEntry) => {
  226. let line;
  227. let column;
  228. // Function entrypoint line/column; used for symbolicating function name
  229. // with legacy source maps (or when --no-function-names is set).
  230. let funcLine;
  231. let funcColumn;
  232. if (entry.funcVirtAddr != null && entry.offset != null) {
  233. // Without debug information.
  234. const funcVirtAddr = parseInt(entry.funcVirtAddr, 10);
  235. const offsetInFunction = parseInt(entry.offset, 10);
  236. // Main bundle always use hard-coded line value 1.
  237. // TODO: support multiple bundle/module.
  238. line = this.options.inputLineStart;
  239. column = funcVirtAddr + offsetInFunction;
  240. funcLine = this.options.inputLineStart;
  241. funcColumn = funcVirtAddr;
  242. } else if (entry.line != null && entry.column != null) {
  243. // For hbc bundle with debug info, name field may already have source
  244. // information for the bundle; we still can use the Metro
  245. // source map to symbolicate the bundle frame addresses further to its
  246. // original source code.
  247. line = entry.line;
  248. column = entry.column;
  249. funcLine = entry.funcLine;
  250. funcColumn = entry.funcColumn;
  251. } else {
  252. // Native frames.
  253. return;
  254. }
  255. // Symbolicate original file/line/column.
  256. const addressOriginal = this.getOriginalPositionDetailsFor(
  257. line,
  258. column,
  259. );
  260. let frameName;
  261. if (addressOriginal.functionName) {
  262. frameName = addressOriginal.functionName;
  263. } else {
  264. frameName = entry.name;
  265. // Symbolicate function name.
  266. if (funcLine != null && funcColumn != null) {
  267. const funcOriginal = this.getOriginalPositionFor(
  268. funcLine,
  269. funcColumn,
  270. );
  271. if (funcOriginal.name != null) {
  272. frameName = funcOriginal.name;
  273. }
  274. } else {
  275. // No function line/column info.
  276. (stderr || stdout).write(
  277. 'Warning: no function prolog line/column info; name may be wrong\n',
  278. );
  279. }
  280. }
  281. // Output format is: funcName(file:line:column)
  282. entry.name = [
  283. frameName,
  284. '(',
  285. [
  286. addressOriginal.source ?? 'null',
  287. addressOriginal.line ?? 'null',
  288. addressOriginal.column ?? 'null',
  289. ].join(':'),
  290. ')',
  291. ].join('');
  292. },
  293. );
  294. stdout.write('Writing to ' + traceFile + '\n');
  295. fs.writeFileSync(traceFile, JSON.stringify(contentJson));
  296. }
  297. /*
  298. * A helper function to return a mapping {line, column} object for a given input
  299. * line and column, and optionally a module ID.
  300. */
  301. getOriginalPositionFor(
  302. lineNumber: ?number,
  303. columnNumber: ?number,
  304. moduleIds: ?ModuleIdsT,
  305. ): {|
  306. line: ?number,
  307. column: ?number,
  308. source: ?string,
  309. name: ?string,
  310. |} {
  311. const position = this.getOriginalPositionDetailsFor(
  312. lineNumber,
  313. columnNumber,
  314. moduleIds,
  315. );
  316. return {
  317. line: position.line,
  318. column: position.column,
  319. source: position.source,
  320. name: position.functionName ? position.functionName : position.name,
  321. };
  322. }
  323. /*
  324. * Symbolicates the JavaScript stack trace extracted from the minidump
  325. * produced by hermes
  326. */
  327. symbolicateHermesMinidumpTrace(
  328. crashInfo: HermesMinidumpCrashInfo,
  329. ): SymbolicatedStackTrace {
  330. throw new Error('Not implemented');
  331. }
  332. /*
  333. * An internal helper function similar to getOriginalPositionFor. This one
  334. * returns both `name` and `functionName` fields so callers can distinguish the
  335. * source of the name.
  336. */
  337. getOriginalPositionDetailsFor(
  338. lineNumber: ?number,
  339. columnNumber: ?number,
  340. moduleIds: ?ModuleIdsT,
  341. ): SymbolicatedStackFrame {
  342. throw new Error('Not implemented');
  343. }
  344. parseFileName(str: string): ModuleIdsT {
  345. throw new Error('Not implemented');
  346. }
  347. }
  348. class SingleMapSymbolicationContext extends SymbolicationContext<SingleMapModuleIds> {
  349. +_segments: {
  350. +[id: string]: {|
  351. +consumer: SourceMapConsumer,
  352. +moduleOffsets: $ReadOnlyArray<number>,
  353. +sourceFunctionsConsumer: ?SourceMetadataMapConsumer,
  354. +hermesOffsets: ?HermesFunctionOffsets,
  355. |},
  356. ...,
  357. };
  358. +_hasLegacySegments: boolean;
  359. constructor(
  360. SourceMapConsumer: SourceMapConsumer,
  361. sourceMapContent: string | MixedSourceMap,
  362. options: ContextOptionsInput = {},
  363. ) {
  364. super(options);
  365. const useFunctionNames = this.options.nameSource === 'function_names';
  366. const sourceMapJson: MixedSourceMap =
  367. typeof sourceMapContent === 'string'
  368. ? JSON.parse(sourceMapContent.replace(/^\)\]\}'/, ''))
  369. : sourceMapContent;
  370. const {x_hermes_function_offsets} = sourceMapJson;
  371. const segments = {
  372. '0': {
  373. consumer: new SourceMapConsumer(sourceMapJson),
  374. moduleOffsets: sourceMapJson.x_facebook_offsets || [],
  375. sourceFunctionsConsumer: useFunctionNames
  376. ? new SourceMetadataMapConsumer(sourceMapJson)
  377. : null,
  378. hermesOffsets: x_hermes_function_offsets,
  379. },
  380. };
  381. if (sourceMapJson.x_facebook_segments) {
  382. for (const key of Object.keys(sourceMapJson.x_facebook_segments)) {
  383. const map = sourceMapJson.x_facebook_segments[key];
  384. segments[key] = {
  385. consumer: new SourceMapConsumer(map),
  386. moduleOffsets: map.x_facebook_offsets || [],
  387. sourceFunctionsConsumer: useFunctionNames
  388. ? new SourceMetadataMapConsumer(map)
  389. : null,
  390. hermesOffsets: map.x_hermes_function_offsets,
  391. };
  392. }
  393. }
  394. this._hasLegacySegments = sourceMapJson.x_facebook_segments != null;
  395. this._segments = segments;
  396. }
  397. symbolicateHermesMinidumpTrace(
  398. crashInfo: HermesMinidumpCrashInfo,
  399. ): SymbolicatedStackTrace {
  400. const symbolicatedTrace = [];
  401. const {callstack} = crashInfo;
  402. if (callstack != null) {
  403. for (const stackItem of callstack) {
  404. if (stackItem.NativeCode) {
  405. symbolicatedTrace.push(stackItem);
  406. } else {
  407. const {
  408. CJSModuleOffset,
  409. SourceURL,
  410. FunctionID,
  411. ByteCodeOffset: localOffset,
  412. } = stackItem;
  413. const moduleInformation = this._hasLegacySegments
  414. ? this.parseFileName(SourceURL)
  415. : UNKNOWN_MODULE_IDS;
  416. const generatedLine = CJSModuleOffset + this.options.inputLineStart;
  417. const segment = this._segments[
  418. moduleInformation.segmentId.toString()
  419. ];
  420. const hermesOffsets = segment?.hermesOffsets;
  421. if (!hermesOffsets) {
  422. symbolicatedTrace.push({
  423. line: null,
  424. column: null,
  425. source: null,
  426. functionName: null,
  427. name: null,
  428. });
  429. } else {
  430. const segmentOffsets = hermesOffsets[Number(CJSModuleOffset)];
  431. const generatedColumn =
  432. segmentOffsets[FunctionID] +
  433. localOffset +
  434. this.options.inputColumnStart;
  435. const originalPosition = this.getOriginalPositionDetailsFor(
  436. generatedLine,
  437. generatedColumn,
  438. moduleInformation,
  439. );
  440. symbolicatedTrace.push(originalPosition);
  441. }
  442. }
  443. }
  444. }
  445. return symbolicatedTrace;
  446. }
  447. /*
  448. * An internal helper function similar to getOriginalPositionFor. This one
  449. * returns both `name` and `functionName` fields so callers can distinguish the
  450. * source of the name.
  451. */
  452. getOriginalPositionDetailsFor(
  453. lineNumber: ?number,
  454. columnNumber: ?number,
  455. moduleIds: ?SingleMapModuleIds,
  456. ): SymbolicatedStackFrame {
  457. // Adjust arguments to source-map's input coordinates
  458. lineNumber =
  459. lineNumber != null
  460. ? lineNumber - this.options.inputLineStart + 1
  461. : lineNumber;
  462. columnNumber =
  463. columnNumber != null
  464. ? columnNumber - this.options.inputColumnStart + 0
  465. : columnNumber;
  466. if (!moduleIds) {
  467. moduleIds = UNKNOWN_MODULE_IDS;
  468. }
  469. let moduleLineOffset = 0;
  470. const metadata = this._segments[moduleIds.segmentId + ''];
  471. const {localId} = moduleIds;
  472. if (localId != null) {
  473. const {moduleOffsets} = metadata;
  474. if (!moduleOffsets) {
  475. throw new Error(
  476. 'Module ID given for a source map that does not have ' +
  477. 'an x_facebook_offsets field',
  478. );
  479. }
  480. if (moduleOffsets[localId] == null) {
  481. throw new Error('Unknown module ID: ' + localId);
  482. }
  483. moduleLineOffset = moduleOffsets[localId];
  484. }
  485. const original = metadata.consumer.originalPositionFor({
  486. line: Number(lineNumber) + moduleLineOffset,
  487. column: Number(columnNumber),
  488. });
  489. if (metadata.sourceFunctionsConsumer) {
  490. original.functionName =
  491. metadata.sourceFunctionsConsumer.functionNameFor(original) || null;
  492. } else {
  493. original.functionName = null;
  494. }
  495. return {
  496. ...original,
  497. line:
  498. original.line != null
  499. ? original.line - 1 + this.options.outputLineStart
  500. : original.line,
  501. column:
  502. original.column != null
  503. ? original.column - 0 + this.options.outputColumnStart
  504. : original.column,
  505. };
  506. }
  507. parseFileName(str: string): SingleMapModuleIds {
  508. return parseSingleMapFileName(str);
  509. }
  510. }
  511. class DirectorySymbolicationContext extends SymbolicationContext<string> {
  512. +_fileMaps: Map<string, SingleMapSymbolicationContext>;
  513. +_rootDir: string;
  514. +_SourceMapConsumer: SourceMapConsumer;
  515. constructor(
  516. SourceMapConsumer: SourceMapConsumer,
  517. rootDir: string,
  518. options: ContextOptionsInput = {},
  519. ) {
  520. super(options);
  521. this._fileMaps = new Map();
  522. this._rootDir = rootDir;
  523. this._SourceMapConsumer = SourceMapConsumer;
  524. }
  525. _loadMap(mapFilename: string): SingleMapSymbolicationContext {
  526. invariant(
  527. fs.existsSync(mapFilename),
  528. `Could not read source map from '${mapFilename}'`,
  529. );
  530. let fileMap = this._fileMaps.get(mapFilename);
  531. if (fileMap == null) {
  532. fileMap = new SingleMapSymbolicationContext(
  533. this._SourceMapConsumer,
  534. fs.readFileSync(mapFilename, 'utf8'),
  535. this.options,
  536. );
  537. this._fileMaps.set(mapFilename, fileMap);
  538. }
  539. return fileMap;
  540. }
  541. /*
  542. * An internal helper function similar to getOriginalPositionFor. This one
  543. * returns both `name` and `functionName` fields so callers can distinguish the
  544. * source of the name.
  545. */
  546. getOriginalPositionDetailsFor(
  547. lineNumber: ?number,
  548. columnNumber: ?number,
  549. filename: ?string,
  550. ): SymbolicatedStackFrame {
  551. invariant(
  552. filename != null,
  553. 'filename is required for DirectorySymbolicationContext',
  554. );
  555. const mapFilename = path.join(this._rootDir, filename + '.map');
  556. if (!fs.existsSync(mapFilename)) {
  557. // Adjust arguments to the output coordinates
  558. lineNumber =
  559. lineNumber != null
  560. ? lineNumber -
  561. this.options.inputLineStart +
  562. this.options.outputLineStart
  563. : lineNumber;
  564. columnNumber =
  565. columnNumber != null
  566. ? columnNumber -
  567. this.options.inputColumnStart +
  568. this.options.outputColumnStart
  569. : columnNumber;
  570. return {
  571. line: lineNumber,
  572. column: columnNumber,
  573. source: filename,
  574. name: null,
  575. functionName: null,
  576. };
  577. }
  578. return this._loadMap(mapFilename).getOriginalPositionDetailsFor(
  579. lineNumber,
  580. columnNumber,
  581. );
  582. }
  583. parseFileName(str: string): string {
  584. return str;
  585. }
  586. }
  587. /*
  588. * If the file name of a stack frame is numeric (+ ".js"), we assume it's a
  589. * lazily injected module coming from a "random access bundle". We are using
  590. * special source maps for these bundles, so that we can symbolicate stack
  591. * traces for multiple injected files with a single source map.
  592. *
  593. * There is also a convention for callsites that are in split segments of a
  594. * bundle, named either `seg-3.js` for segment #3 for example, or `seg-3_5.js`
  595. * for module #5 of segment #3 of a segmented RAM bundle.
  596. */
  597. function parseSingleMapFileName(str: string): SingleMapModuleIds {
  598. const modMatch = str.match(/^(\d+).js$/);
  599. if (modMatch != null) {
  600. return {segmentId: 0, localId: Number(modMatch[1])};
  601. }
  602. const segMatch = str.match(/^seg-(\d+)(?:_(\d+))?.js$/);
  603. if (segMatch != null) {
  604. return {
  605. segmentId: Number(segMatch[1]),
  606. localId: segMatch[2] ? Number(segMatch[2]) : null,
  607. };
  608. }
  609. return UNKNOWN_MODULE_IDS;
  610. }
  611. function createContext(
  612. SourceMapConsumer: SourceMapConsumer,
  613. sourceMapContent: string | MixedSourceMap,
  614. options: ContextOptionsInput = {},
  615. ): SingleMapSymbolicationContext {
  616. return new SingleMapSymbolicationContext(
  617. SourceMapConsumer,
  618. sourceMapContent,
  619. options,
  620. );
  621. }
  622. function unstable_createDirectoryContext(
  623. SourceMapConsumer: SourceMapConsumer,
  624. rootDir: string,
  625. options: ContextOptionsInput = {},
  626. ): DirectorySymbolicationContext {
  627. return new DirectorySymbolicationContext(SourceMapConsumer, rootDir, options);
  628. }
  629. function getOriginalPositionFor<ModuleIdsT>(
  630. lineNumber: ?number,
  631. columnNumber: ?number,
  632. moduleIds: ?ModuleIdsT,
  633. context: SymbolicationContext<ModuleIdsT>,
  634. ): {|
  635. line: ?number,
  636. column: ?number,
  637. source: ?string,
  638. name: ?string,
  639. |} {
  640. return context.getOriginalPositionFor(lineNumber, columnNumber, moduleIds);
  641. }
  642. function symbolicate<ModuleIdsT>(
  643. stackTrace: string,
  644. context: SymbolicationContext<ModuleIdsT>,
  645. ): string {
  646. return context.symbolicate(stackTrace);
  647. }
  648. function symbolicateProfilerMap<ModuleIdsT>(
  649. mapFile: string,
  650. context: SymbolicationContext<ModuleIdsT>,
  651. ): string {
  652. return context.symbolicateProfilerMap(mapFile);
  653. }
  654. function symbolicateAttribution<ModuleIdsT>(
  655. obj: SizeAttributionMap,
  656. context: SymbolicationContext<ModuleIdsT>,
  657. ): SizeAttributionMap {
  658. return context.symbolicateAttribution(obj);
  659. }
  660. function symbolicateChromeTrace<ModuleIdsT>(
  661. traceFile: string,
  662. {
  663. stdout,
  664. stderr,
  665. }: {
  666. stdout: stream$Writable,
  667. stderr: stream$Writable,
  668. ...
  669. },
  670. context: SymbolicationContext<ModuleIdsT>,
  671. ): void {
  672. return context.symbolicateChromeTrace(traceFile, {stdout, stderr});
  673. }
  674. module.exports = {
  675. createContext,
  676. unstable_createDirectoryContext,
  677. getOriginalPositionFor,
  678. parseFileName: parseSingleMapFileName,
  679. symbolicate,
  680. symbolicateProfilerMap,
  681. symbolicateAttribution,
  682. symbolicateChromeTrace,
  683. SourceMetadataMapConsumer,
  684. };