mmap.js revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5mmap = new (function() { 6 7this.COL_START = 0; 8this.COL_END = 1; 9this.COL_LEN = 2; 10this.COL_PROT = 3; 11this.COL_PRIV_DIRTY = 4; 12this.COL_PRIV_CLEAN = 5; 13this.COL_SHARED_DIRTY = 6; 14this.COL_SHARED_CLEAN = 7; 15this.COL_FILE = 8; 16this.COL_RESIDENT = 10; 17this.SHOW_COLUMNS = [0, 1, 2, 3, 4, 5, 6, 7, 8]; 18this.PAGE_SIZE = 4096; 19 20this.mapsData_ = null; 21this.mapsTable_ = null; 22this.mapsFilter_ = null; 23 24this.onDomReady_ = function() { 25 $('#mm-lookup-addr').on('change', this.lookupAddress.bind(this)); 26 $('#mm-filter-file').on('change', this.applyMapsTableFilters_.bind(this)); 27 $('#mm-filter-prot').on('change', this.applyMapsTableFilters_.bind(this)); 28 $('#mm-filter-clear').on('click', this.resetMapsTableFilters_.bind(this)); 29 30 // Create the mmaps table. 31 this.mapsTable_ = new google.visualization.Table($('#mm-table')[0]); 32 google.visualization.events.addListener( 33 this.mapsTable_, 'select', this.onMmapTableRowSelect_.bind(this)); 34 $('#mm-table').on('dblclick', this.onMmapTableDblClick_.bind(this)); 35}; 36 37this.dumpMmaps = function(targetProcUri) { 38 if (!targetProcUri) 39 return; 40 webservice.ajaxRequest('/dump/mmap/' + targetProcUri, 41 this.onDumpAjaxResponse_.bind(this)); 42 rootUi.showDialog('Dumping memory maps for ' + targetProcUri + '...'); 43}; 44 45this.onDumpAjaxResponse_ = function(data) { 46 $('#mm-filter-file').val(''); 47 $('#mm-filter-prot').val(''); 48 this.mapsData_ = new google.visualization.DataTable(data); 49 this.mapsFilter_ = new google.visualization.DataView(this.mapsData_); 50 this.mapsFilter_.setColumns(this.SHOW_COLUMNS); 51 this.applyMapsTableFilters_(); 52 rootUi.hideDialog(); 53}; 54 55this.applyMapsTableFilters_ = function() { 56 // Filters the rows according to the user-provided file and prot regexps. 57 if (!this.mapsFilter_) 58 return; 59 60 var fileRx = $('#mm-filter-file').val(); 61 var protRx = $('#mm-filter-prot').val(); 62 var rows = []; 63 var totPrivDirty = 0; 64 var totPrivClean = 0; 65 var totSharedDirty = 0; 66 var totSharedClean = 0; 67 68 for (var row = 0; row < this.mapsData_.getNumberOfRows(); ++row) { 69 mappedFile = this.mapsData_.getValue(row, this.COL_FILE); 70 protFlags = this.mapsData_.getValue(row, this.COL_PROT); 71 if (!mappedFile.match(fileRx) || !protFlags.match(protRx)) 72 continue; 73 rows.push(row); 74 totPrivDirty += this.mapsData_.getValue(row, this.COL_PRIV_DIRTY); 75 totPrivClean += this.mapsData_.getValue(row, this.COL_PRIV_CLEAN); 76 totSharedDirty += this.mapsData_.getValue(row,this.COL_SHARED_DIRTY); 77 totSharedClean += this.mapsData_.getValue(row, this.COL_SHARED_CLEAN); 78 } 79 80 this.mapsFilter_.setRows(rows); 81 $('#mm-totals-priv-dirty').text(totPrivDirty); 82 $('#mm-totals-priv-clean').text(totPrivClean); 83 $('#mm-totals-shared-dirty').text(totSharedDirty); 84 $('#mm-totals-shared-clean').text(totSharedClean); 85 this.redraw(); 86}; 87 88this.resetMapsTableFilters_ = function() { 89 $('#mm-filter-file').val(''); 90 $('#mm-filter-prot').val(''); 91 this.applyMapsTableFilters_(); 92}; 93 94this.onMmapTableRowSelect_ = function() { 95 // Update the memory totals for the selected rows. 96 if (!this.mapsFilter_) 97 return; 98 99 var totPrivDirty = 0; 100 var totPrivClean = 0; 101 var totSharedDirty = 0; 102 var totSharedClean = 0; 103 104 this.mapsTable_.getSelection().forEach(function(sel) { 105 var row = sel.row; 106 totPrivDirty += this.mapsFilter_.getValue(row, this.COL_PRIV_DIRTY); 107 totPrivClean += this.mapsFilter_.getValue(row, this.COL_PRIV_CLEAN); 108 totSharedDirty += this.mapsFilter_.getValue(row,this.COL_SHARED_DIRTY); 109 totSharedClean += this.mapsFilter_.getValue(row, this.COL_SHARED_CLEAN); 110 }, this); 111 $('#mm-selected-priv-dirty').text(totPrivDirty); 112 $('#mm-selected-priv-clean').text(totPrivClean); 113 $('#mm-selected-shared-dirty').text(totSharedDirty); 114 $('#mm-selected-shared-clean').text(totSharedClean); 115}; 116 117this.onMmapTableDblClick_ = function() { 118 // Show resident pages for the selected mapping. 119 var PAGES_PER_ROW = 16; 120 121 if (!this.mapsData_) 122 return; 123 124 var sel = this.mapsTable_.getSelection(); 125 if (sel.length == 0) 126 return; 127 128 // |sel| returns the row index in the current view, which might be filtered. 129 // Need to walk back in the mapsFilter_.getViewRows to get the actual row 130 // index in the original table. 131 var row = this.mapsFilter_.getViewRows()[sel[0].row]; 132 var arr = JSON.parse(this.mapsData_.getValue(row, this.COL_RESIDENT)); 133 var table = $('<table class="mm-resident-table"/>'); 134 var curRow = $('<tr/>'); 135 table.append(curRow); 136 137 for (var i = 0; i < arr.length; ++i) { 138 for (var j = 0; j < 8; ++j) { 139 var pageIdx = i * 8 + j; 140 var resident = !!(arr[i] & (1 << j)); 141 if (pageIdx % PAGES_PER_ROW == 0) { 142 curRow = $('<tr/>'); 143 table.append(curRow); 144 } 145 var hexAddr = (pageIdx * this.PAGE_SIZE).toString(16); 146 var cell = $('<td/>').text(hexAddr); 147 if (resident) 148 cell.addClass('resident') 149 curRow.append(cell); 150 } 151 } 152 rootUi.showDialog(table, 'Resident page list'); 153}; 154 155this.redraw = function() { 156 if (!this.mapsFilter_) 157 return; 158 this.mapsTable_.draw(this.mapsFilter_); 159}; 160 161this.lookupAddress = function() { 162 // Looks up the user-provided address in the mmap table and highlights the 163 // row containing the map (if found). 164 if (!this.mapsData_) 165 return; 166 167 addr = parseInt($('#mm-lookup-addr').val(), 16); 168 $('#mm-lookup-offset').val(''); 169 if (!addr) 170 return; 171 172 this.resetMapsTableFilters_(); 173 174 var lbound = 0; 175 var ubound = this.mapsData_.getNumberOfRows() - 1; 176 while (lbound <= ubound) { 177 var row = ((lbound + ubound) / 2) >> 0; 178 var start = parseInt(this.mapsData_.getValue(row, this.COL_START), 16); 179 var end = parseInt(this.mapsData_.getValue(row, this.COL_END), 16); 180 if (addr < start){ 181 ubound = row - 1; 182 } 183 else if (addr > end) { 184 lbound = row + 1; 185 } 186 else { 187 $('#mm-lookup-offset').val((addr - start).toString(16)); 188 this.mapsTable_.setSelection([{row: row, column: null}]); 189 // Scroll to row. 190 $('#wrapper').scrollTop( 191 $('#mm-table .google-visualization-table-tr-sel').offset().top); 192 break; 193 } 194 } 195}; 196 197$(document).ready(this.onDomReady_.bind(this)); 198 199})();