chromium/native_client_sdk/src/examples/tutorial/debugging/example.js

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var lastModuleError = '';
var crashed = false;

function domContentLoaded(name, tc, config, width, height) {
  common.attachDefaultListeners();
  common.createNaClModule(name, tc, config, width, height);

  updateStatus('Page Loaded');
}

// Indicate success when the NaCl module has loaded.
function moduleDidLoad() {
  updateStatus('LOADED');
  setTimeout(boom, 2000);
}

function findAddress(addr, map) {
  if (map.length < 1) {
    return 'MAP Unavailable';
  }
  if (addr < map[0].offs) {
    return 'Invalid Address';
  }

  for (var i = 1; i < map.length; i++) {
    if (addr < map[i].offs) {
      var offs = addr - map[i - 1].offs;
      var filename = map[i - 1].file;

      // Force filename to 50 chars
      if (filename) {
        if (filename.length > 50) {
            filename = '...' + filename.substr(filename.length - 47);
        }
      } else {
        filename = 'Unknown';
      }
      while (filename.length < 50) {
        filename = ' ' + filename;
      }
      return filename + ' ' + map[i - 1].name + ' + 0x' + offs.toString(16);
    }
  }

  var last = map.length - 1;
  return filename + ' ' + map[last].name + ' + 0x' + offs.toString(16);
}

function buildTextMap(map) {
  // The expected format of the map file is this:
  // ...
  // .text     0x00000000000201e0     0x10e0 newlib/Debug/debugging_x86_64.o
  //           0x0000000000020280                layer5
  //           0x00000000000202e0                layer4
  //           0x0000000000020320                layer3
  //           0x0000000000020380                layer2
  //           0x00000000000203e0                layer1
  //           0x0000000000020460                NexeMain
  // ...
  var lines = map.split('\n');
  var orderedMap = [];
  var inTextSection = false;
  var fileName = '';

  for (var i = 0; i < lines.length; i++) {
    var line = lines[i];

    if (inTextSection) {
      //   <hex address>   <symbol name>
      var vals = line.trim().split(/\s+/);
      if (vals.length != 2) {
        inTextSection = false;
        continue;
      }

      var obj = {
        offs: parseInt(vals[0], 16),
        name: vals[1],
        file: fileName
      };

      orderedMap.push(obj);
    } else {
      // If line starts with .text:
      if (line.lastIndexOf(' .text', 0) === 0) {
        inTextSection = true;
        // .text    <hex address>   <size>  <filename>
        var vals = line.trim().split(/\s+/);
        fileName = vals[3];
      }
    }
  }

  orderedMap.sort(function(a, b) { return a.offs - b.offs; });
  return orderedMap;
}

function updateStack(traceinfo, map) {
  map = buildTextMap(map);
  var text = 'Stack Trace\n';
  for (var i = 0; i < traceinfo.frames.length; i++) {
    var frame = traceinfo.frames[i];
    var addr = findAddress(frame.prog_ctr, map);
    text += '[' + i.toString(10) + '] ' + addr + '\n';
  }
  document.getElementById('trace').value = text;
}

function fetchMap(url, traceinfo) {
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.open('GET', url, true);
  xmlhttp.onload = function() {
    updateStack(traceinfo, this.responseText);
  };
  xmlhttp.traceinfo = traceinfo;
  xmlhttp.send();
}

// Handle a message coming from the NaCl module.
function handleMessage(message_event) {
  msg_type = message_event.data.substring(0, 4);
  msg_data = message_event.data.substring(5, message_event.data.length);
  if (msg_type == 'LOG:') {
    document.getElementById('log').value += msg_data + '\n';
    return;
  }
  if (msg_type == 'TRC:') {
    crashed = true;
    document.getElementById('json').value = msg_data;
    crash_info = JSON.parse(msg_data);
    updateStatus('Crash Reported');
    src = common.naclModule.getAttribute('path');
    fetchMap(src + '/debugging_' + crash_info['arch'] + '.map', crash_info);
    return;
  }
}

function updateStatus(message) {
  common.updateStatus(message);

  if (message)
    document.getElementById('log').value += message + '\n';
}

function boom() {
  if (!crashed) {
    updateStatus('Send BOOM');
    common.naclModule.postMessage('BOOM');
  }
}