diff --git a/src/debugger.js b/src/debugger.js index 18c5762..a4a5921 100644 --- a/src/debugger.js +++ b/src/debugger.js @@ -10,59 +10,59 @@ const { D } = require('./util'); function Debugger() { this.connection = null; this.ons = {}; - this.breakpoints = { all:[], enabled:{}, bysrcloc:{} }; + this.breakpoints = { all: [], enabled: {}, bysrcloc: {} }; this.JDWP = new _JDWP(); this.session = null; this.globals = Debugger.globals; } Debugger.globals = { - portrange : {lowest:31000, highest:31099}, - inuseports : [], - debuggers : {}, - reserveport:function() { - // choose a random port to use each time - for (var i=0; i < 10000; i++) { - var portidx = ((Math.random()*100)|0); - if (this.inuseports.includes(portidx)) - continue; // try again - this.inuseports.push(portidx); - return this.portrange.lowest+portidx; - } - }, - freeport : function(port) { - var iuidx = this.inuseports.indexOf(port - this.portrange.lowest); - if (iuidx >= 0) this.inuseports.splice(iuidx, 1); + portrange: { lowest: 31000, highest: 31099 }, + inuseports: [], + debuggers: {}, + reserveport: function () { + // choose a random port to use each time + for (var i = 0; i < 10000; i++) { + var portidx = ((Math.random() * 100) | 0); + if (this.inuseports.includes(portidx)) + continue; // try again + this.inuseports.push(portidx); + return this.portrange.lowest + portidx; } + }, + freeport: function (port) { + var iuidx = this.inuseports.indexOf(port - this.portrange.lowest); + if (iuidx >= 0) this.inuseports.splice(iuidx, 1); + } }; Debugger.prototype = { - on : function(which, context, data, fn) { - if (!fn && !data && typeof(context)==='function') { + on: function (which, context, data, fn) { + if (!fn && !data && typeof (context) === 'function') { fn = context; context = data = null; } - else if (!fn && typeof(data)==='function') { + else if (!fn && typeof (data) === 'function') { fn = data; data = null; } if (!this.ons[which]) this.ons[which] = []; this.ons[which].push({ - context:context,data:data,fn:fn + context: context, data: data, fn: fn }); return this; }, - _trigger : function(which, e) { + _trigger: function (which, e) { var k = this.ons[which]; if (!k || !k.length) return this; k = k.slice(); - e = e||{}; + e = e || {}; e.dbgr = this; - for (var i=0; i < k.length; i++) { + for (var i = 0; i < k.length; i++) { e.data = k[i].data; - try { k[i].fn.call(k[i].context, e)} - catch(ex) { - D('Exception in event trigger: '+ex.message); + try { k[i].fn.call(k[i].context, e) } + catch (ex) { + D('Exception in event trigger: ' + ex.message); } } return this; @@ -71,140 +71,140 @@ Debugger.prototype = { startDebugSession(build, deviceid, launcherActivity) { return this.newSession(build, deviceid) .runapp('debug', launcherActivity, this) - .then(function(deviceid) { + .then(function (deviceid) { return this.getDebuggablePIDs(this.session.deviceid, this); }) - .then(function(pids, dbgr) { + .then(function (pids, dbgr) { // choose the last pid in the list - var pid = pids[pids.length-1]; + var pid = pids[pids.length - 1]; // after connect(), the caller must call resume() to begin return dbgr.connect(pid, dbgr); }) }, runapp(action, launcherActivity) { - // older (<3) versions of Android only allow target components to be specified with -n - var launchcmdparams = ['--activity-brought-to-front','-a android.intent.action.MAIN','-c android.intent.category.LAUNCHER','-n '+ this.session.build.pkgname+'/'+launcherActivity]; - if (action==='debug') { - launchcmdparams.splice(0,0,'-D'); - } - var x = { - dbgr:this, - shell_cmd: { - command: 'am start '+launchcmdparams.join(' '), - untilclosed:true, - }, - retries: { - count:10,pause:1000, - }, - deviceid:this.session.deviceid, - deferred: $.Deferred(), - }; - tryrunapp(x); - function tryrunapp(x) { - var adb = new ADBClient(x.deviceid); - adb.shell_cmd(x.shell_cmd) - .then(function(stdout) { - // failures: - // Error: Activity not started... - var m = stdout.match(/Error:.*/g); - if (m) { - if (--x.retries.count) { - setTimeout(function(o) { - tryrunapp(o); - }, x.retries.pause, x); - return; - } - return x.deferred.reject({cat:'cmd', msg: m[0]}); - } + // older (<3) versions of Android only allow target components to be specified with -n + var launchcmdparams = ['--activity-brought-to-front', '-a android.intent.action.MAIN', '-c android.intent.category.LAUNCHER', '-n ' + this.session.build.pkgname + '/' + launcherActivity]; + if (action === 'debug') { + launchcmdparams.splice(0, 0, '-D'); + } + var x = { + dbgr: this, + shell_cmd: { + command: 'am start ' + launchcmdparams.join(' '), + untilclosed: true, + }, + retries: { + count: 10, pause: 1000, + }, + deviceid: this.session.deviceid, + deferred: $.Deferred(), + }; + tryrunapp(x); + function tryrunapp(x) { + var adb = new ADBClient(x.deviceid); + adb.shell_cmd(x.shell_cmd) + .then(function (stdout) { + // failures: + // Error: Activity not started... + var m = stdout.match(/Error:.*/g); + if (m) { + if (--x.retries.count) { + setTimeout(function (o) { + tryrunapp(o); + }, x.retries.pause, x); + return; + } + return x.deferred.reject({ cat: 'cmd', msg: m[0] }); + } // running the JDWP command so soon after launching hangs, so give it a breather before continuing setTimeout(x => { x.deferred.resolveWith(x.dbgr, [x.deviceid]) }, 1000, x); - }) - .fail(function(err) { - }); - } - return x.deferred; - }, + }) + .fail(function (err) { + }); + } + return x.deferred; + }, - newSession : function(build, deviceid) { + newSession: function (build, deviceid) { this.session = { build: build, deviceid: deviceid, - apilevel:0, + apilevel: 0, adbclient: null, stoppedlocation: null, - classes:{}, + classes: {}, // classprepare notifier done - cpndone:false, - preparedclasses:[], + cpndone: false, + preparedclasses: [], } return this; }, /* return a list of deviceids available for debugging */ - list_devices : function(extra) { + list_devices: function (extra) { return new ADBClient().list_devices(extra); }, - getDebuggablePIDs : function(deviceid, extra) { + getDebuggablePIDs: function (deviceid, extra) { return new ADBClient(deviceid).jdwp_list({ - ths:this, - extra:extra, + ths: this, + extra: extra, }) }, - getDebuggableProcesses : function(deviceid, extra) { + getDebuggableProcesses: function (deviceid, extra) { var info = { - debugger:this, + debugger: this, adbclient: new ADBClient(deviceid), - extra:extra, + extra: extra, }; return info.adbclient.jdwp_list({ - ths:this, - extra:info, + ths: this, + extra: info, }) - .then(function(jdwps, info) { - if (!jdwps.length) - return $.Deferred().resolveWith(this,[[], info.extra]); - info.jdwps = jdwps; - // retrieve the ps list from the device - return info.adbclient.shell_cmd({ - ths:this, - extra:info, - command:'ps', - untilclosed:true, - }).then(function(stdout, info) { - // output should look something like... - // USER PID PPID VSIZE RSS WCHAN PC NAME - // u0_a153 32721 1452 1506500 37916 ffffffff 00000000 S com.example.somepkg - // but we cope with variations so long as PID and NAME exist - var lines = stdout.split(/\r?\n|\r/g); - var hdrs = (lines.shift()||'').trim().toUpperCase().split(/\s+/); - var pidindex = hdrs.indexOf('PID'); - var nameindex = hdrs.indexOf('NAME'); - var result = {deviceid:info.adbclient.deviceid,name:{},jdwp:{},all:[]}; - if (pidindex<0||nameindex<0) - return $.Deferred().resolveWith(null,[[],info.extra]); - // scan the list looking for matching pids... - for (var i=0; i < lines.length; i++) { - var entries=lines[i].trim().replace(/ [S] /,' ').split(/\s+/); - if (entries.length != hdrs.length) continue; - var jdwpidx = info.jdwps.indexOf(entries[pidindex]); - if (jdwpidx < 0) continue; - // we found a match - var entry = { - jdwp: entries[pidindex], - name: entries[nameindex], - }; - result.all.push(entry); - result.name[entry.name] = entry; - result.jdwp[entry.jdwp] = entry; - } - return $.Deferred().resolveWith(this,[result, info.extra]); - }) - }); + .then(function (jdwps, info) { + if (!jdwps.length) + return $.Deferred().resolveWith(this, [[], info.extra]); + info.jdwps = jdwps; + // retrieve the ps list from the device + return info.adbclient.shell_cmd({ + ths: this, + extra: info, + command: 'ps', + untilclosed: true, + }).then(function (stdout, info) { + // output should look something like... + // USER PID PPID VSIZE RSS WCHAN PC NAME + // u0_a153 32721 1452 1506500 37916 ffffffff 00000000 S com.example.somepkg + // but we cope with variations so long as PID and NAME exist + var lines = stdout.split(/\r?\n|\r/g); + var hdrs = (lines.shift() || '').trim().toUpperCase().split(/\s+/); + var pidindex = hdrs.indexOf('PID'); + var nameindex = hdrs.indexOf('NAME'); + var result = { deviceid: info.adbclient.deviceid, name: {}, jdwp: {}, all: [] }; + if (pidindex < 0 || nameindex < 0) + return $.Deferred().resolveWith(null, [[], info.extra]); + // scan the list looking for matching pids... + for (var i = 0; i < lines.length; i++) { + var entries = lines[i].trim().replace(/ [S] /, ' ').split(/\s+/); + if (entries.length != hdrs.length) continue; + var jdwpidx = info.jdwps.indexOf(entries[pidindex]); + if (jdwpidx < 0) continue; + // we found a match + var entry = { + jdwp: entries[pidindex], + name: entries[nameindex], + }; + result.all.push(entry); + result.name[entry.name] = entry; + result.jdwp[entry.jdwp] = entry; + } + return $.Deferred().resolveWith(this, [result, info.extra]); + }) + }); }, /* attach to the debuggable pid @@ -212,14 +212,14 @@ Debugger.prototype = { setup class loader notifications and call anyone waiting for us. If anything fails, we call disconnect() to return to a sense of normality. */ - connect : function(jdwpid, extra) { - switch(this.status()) { - case 'connected': + connect: function (jdwpid, extra) { + switch (this.status()) { + case 'connected': // already connected - just resolve return $.Deferred().resolveWith(this, [extra]); - case 'connecting': + case 'connecting': // wait for the connection to complete (or fail) - var x = { deferred:$.Deferred(), extra: extra }; + var x = { deferred: $.Deferred(), extra: extra }; this.connection.connectingpromises.push(x); return x.deferred; default: @@ -236,83 +236,83 @@ Debugger.prototype = { // from this point on, we are in the "connecting" state until the JDWP handshake is complete // (and we mark as connected) or we fail and return to the disconnected state this.connection = { - jdwp:jdwpid, - localport:this.globals.reserveport(), - portforwarding:false, - connected:false, - connectingpromises:[], + jdwp: jdwpid, + localport: this.globals.reserveport(), + portforwarding: false, + connected: false, + connectingpromises: [], }; // setup port forwarding return new ADBClient(this.session.deviceid).jdwp_forward({ - ths:this, - extra:info, - localport:this.connection.localport, - jdwp:this.connection.jdwp, + ths: this, + extra: info, + localport: this.connection.localport, + jdwp: this.connection.jdwp, }) - .then(function(info) { - this.connection.portforwarding = true; - // after this, the client keeps an open connection until - // jdwp_disconnect() is called - this.session.adbclient = new ADBClient(this.session.deviceid); - return this.session.adbclient.jdwp_connect({ - ths:this, - extra:info, - localport: this.connection.localport, - onreply: this._onjdwpmessage, - }); - }) - .then(function(info) { - // handshake has completed - this.connection.connected = true; - // call suspend first - we shouldn't really need to do this (as the debugger - // is already suspended and will not resume until we tell it), but if we - // don't do this, it logs a complaint... - return this.suspend(); - }) - .then(function() { - return this.session.adbclient.jdwp_command({ - ths: this, - cmd: this.JDWP.Commands.idsizes(), - }); - }) - .then(function(idsizes) { - // set the class loader event notifier so we can set breakpoints... - this.JDWP.setIDSizes(idsizes); - return this._initbreakpoints(); - }) - .then(function() { - return new ADBClient(this.session.deviceid).shell_cmd({ - ths:this, - command:'getprop ro.build.version.sdk', - }); - }) - .then(function(apilevel) { - this.session.apilevel = apilevel.trim(); - // at this point, we are ready to go - all the caller needs to do is call resume(). - // resolve all the connection promises for those waiting on us (usually none) - var cp = this.connection.connectingpromises; - var deferreds = [this, info]; - delete this.connection.connectingpromises; - for (var i=0; i < cp.length; i++) { - deferreds.push(cp[i].deferred); - cp[i].deferred.resolveWith(this, [cp[i].extra]); - } - return $.when.apply($, deferreds).then(function(dbgr, info) { - return $.Deferred().resolveWith(dbgr, [info.extra]); + .then(function (info) { + this.connection.portforwarding = true; + // after this, the client keeps an open connection until + // jdwp_disconnect() is called + this.session.adbclient = new ADBClient(this.session.deviceid); + return this.session.adbclient.jdwp_connect({ + ths: this, + extra: info, + localport: this.connection.localport, + onreply: this._onjdwpmessage, + }); + }) + .then(function (info) { + // handshake has completed + this.connection.connected = true; + // call suspend first - we shouldn't really need to do this (as the debugger + // is already suspended and will not resume until we tell it), but if we + // don't do this, it logs a complaint... + return this.suspend(); + }) + .then(function () { + return this.session.adbclient.jdwp_command({ + ths: this, + cmd: this.JDWP.Commands.idsizes(), + }); + }) + .then(function (idsizes) { + // set the class loader event notifier so we can set breakpoints... + this.JDWP.setIDSizes(idsizes); + return this._initbreakpoints(); + }) + .then(function () { + return new ADBClient(this.session.deviceid).shell_cmd({ + ths: this, + command: 'getprop ro.build.version.sdk', + }); + }) + .then(function (apilevel) { + this.session.apilevel = apilevel.trim(); + // at this point, we are ready to go - all the caller needs to do is call resume(). + // resolve all the connection promises for those waiting on us (usually none) + var cp = this.connection.connectingpromises; + var deferreds = [this, info]; + delete this.connection.connectingpromises; + for (var i = 0; i < cp.length; i++) { + deferreds.push(cp[i].deferred); + cp[i].deferred.resolveWith(this, [cp[i].extra]); + } + return $.when.apply($, deferreds).then(function (dbgr, info) { + return $.Deferred().resolveWith(dbgr, [info.extra]); + }) + }) + .then(function () { + this._trigger('connected'); + }) + .fail(function (err) { + this.connection.err = err; + // force a return to the disconnected state + this.disconnect(); }) - }) - .then(function() { - this._trigger('connected'); - }) - .fail(function(err) { - this.connection.err = err; - // force a return to the disconnected state - this.disconnect(); - }) }, - _onjdwpmessage : function(data) { + _onjdwpmessage: function (data) { // decodereply will resolve the promise associated with // any command this reply is in response to. var reply = this.JDWP.decodereply(this, data); @@ -322,38 +322,38 @@ Debugger.prototype = { case 100: // vm disconnected - sent by plugin this.disconnect(); - break; + break; } } } }, - ensureconnected : function(extra) { + ensureconnected: function (extra) { // passing null as the jdwpid will cause a fail if the client is not connected (or connecting) return this.connect(null, extra); }, - status : function() { + status: function () { if (!this.connection) return "disconnected"; if (this.connection.connected) return "connected"; return "connecting"; }, - forcestop : function(extra) { + forcestop: function (extra) { return this.ensureconnected() - .then(function() { + .then(function () { return new ADBClient(this.session.deviceid).shell_cmd({ - command:'am force-stop '+ this.session.build.pkgname, + command: 'am force-stop ' + this.session.build.pkgname, }); }) }, - disconnect : function(extra) { + disconnect: function (extra) { // disconnect is called from a variety of failure scenarios // so it must be fairly robust in how it undoes stuff const current_state = this.status(); if (!this.connection) - return $.Deferred().resolveWith(this, [current_state,extra]); + return $.Deferred().resolveWith(this, [current_state, extra]); var info = { connection: this.connection, @@ -366,7 +366,7 @@ Debugger.prototype = { // fail any waiting for the connection to complete var cp = info.connection.connectingpromises; if (cp) { - for (var i=0; i < cp.length; i++) { + for (var i = 0; i < cp.length; i++) { cp[i].deferred.rejectWith(this, [info.connection.err]); } } @@ -377,22 +377,22 @@ Debugger.prototype = { this._trigger('disconnect'); // perform the JDWP disconnect - info.jdwpdisconnect = info.connection.connected - ? this.session.adbclient.jdwp_disconnect({ths:this, extra:info}) + info.jdwpdisconnect = info.connection.connected + ? this.session.adbclient.jdwp_disconnect({ ths: this, extra: info }) : $.Deferred().resolveWith(this, [info]); return info.jdwpdisconnect - .then(function(info) { + .then(function (info) { this.session.adbclient = null; // undo the portforwarding // todo: replace remove_all with remove_port - info.pfremove = info.connection.portforwarding - ? new ADBClient(this.session.deviceid).forward_remove_all({ths:this, extra:info}) + info.pfremove = info.connection.portforwarding + ? new ADBClient(this.session.deviceid).forward_remove_all({ ths: this, extra: info }) : $.Deferred().resolveWith(this, [info]); return info.pfremove; }) - .then(function(info) { + .then(function (info) { // mark the port as freed if (info.connection.portforwarding) { this.globals.freeport(info.connection.localport) @@ -402,9 +402,9 @@ Debugger.prototype = { }); }, - allthreads : function(extra) { + allthreads: function (extra) { return this.ensureconnected(extra) - .then(function(extra) { + .then(function (extra) { return this.session.adbclient.jdwp_command({ ths: this, extra: extra, @@ -413,9 +413,9 @@ Debugger.prototype = { }); }, - suspend : function(extra) { + suspend: function (extra) { return this.ensureconnected(extra) - .then(function(extra) { + .then(function (extra) { this._trigger('suspending'); return this.session.adbclient.jdwp_command({ ths: this, @@ -423,14 +423,14 @@ Debugger.prototype = { cmd: this.JDWP.Commands.suspend(), }); }) - .then(function() { + .then(function () { this._trigger('suspended'); }); }, - resume : function(extra) { + resume: function (extra) { return this.ensureconnected(extra) - .then(function(extra) { + .then(function (extra) { this._trigger('resuming'); this.session.stoppedlocation = null; return this.session.adbclient.jdwp_command({ @@ -439,15 +439,15 @@ Debugger.prototype = { cmd: this.JDWP.Commands.resume(), }); }) - .then(function(decoded, extra) { + .then(function (decoded, extra) { this._trigger('resumed'); return extra; }); }, - _resumesilent : function() { + _resumesilent: function () { return this.ensureconnected() - .then(function() { + .then(function () { this.session.stoppedlocation = null; return this.session.adbclient.jdwp_command({ ths: this, @@ -457,66 +457,66 @@ Debugger.prototype = { }); }, - step : function(steptype, threadid) { - var x = {steptype:steptype, threadid:threadid}; + step: function (steptype, threadid) { + var x = { steptype: steptype, threadid: threadid }; return this.ensureconnected(x) - .then(function(x) { + .then(function (x) { this._trigger('stepping'); return this._setupstepevent(x.steptype, x.threadid); }) - .then(function() { + .then(function () { return this._resumesilent(); }); }, - _splitsrcfpn: function(srcfpn) { + _splitsrcfpn: function (srcfpn) { var m = srcfpn.match(/^\/([^/]+(?:\/[^/]+)*)?\/([^./]+)\.java$/); return { - pkg:m[1].replace(/\/+/g,'.'), - type:m[2], - qtype:m[1]+'/'+m[2], + pkg: m[1].replace(/\/+/g, '.'), + type: m[2], + qtype: m[1] + '/' + m[2], } }, - getbreakpoint : function(srcfpn,line) { + getbreakpoint: function (srcfpn, line) { var cls = this._splitsrcfpn(srcfpn); - var bp = this.breakpoints.bysrcloc[cls.qtype+':'+line]; + var bp = this.breakpoints.bysrcloc[cls.qtype + ':' + line]; return bp; }, - getbreakpoints : function(filterfn) { - var x = this.breakpoints.all.reduce(function(x, bp) { + getbreakpoints: function (filterfn) { + var x = this.breakpoints.all.reduce(function (x, bp) { if (x.filterfn(bp)) x.res.push(bp); return x; - }, {filterfn:filterfn, res:[]}); + }, { filterfn: filterfn, res: [] }); return x.res; }, - getallbreakpoints : function() { + getallbreakpoints: function () { return this.breakpoints.all.slice(); }, - setbreakpoint : function(srcfpn, line) { + setbreakpoint: function (srcfpn, line) { var cls = this._splitsrcfpn(srcfpn); - var bid = cls.qtype+':'+line; + var bid = cls.qtype + ':' + line; var newbp = this.breakpoints.bysrcloc[bid]; if (newbp) return newbp; newbp = { - id:bid, - srcfpn:srcfpn, + id: bid, + srcfpn: srcfpn, qtype: cls.qtype, pkg: cls.pkg, type: cls.type, - linenum:line, - sigpattern: new RegExp('^L'+cls.qtype+'([$][$a-zA-Z0-9_]+)?;$'), - state:'set'// set,notloaded,enabled,removed + linenum: line, + sigpattern: new RegExp('^L' + cls.qtype + '([$][$a-zA-Z0-9_]+)?;$'), + state: 'set'// set,notloaded,enabled,removed }; this.breakpoints.all.push(newbp); this.breakpoints.bysrcloc[bid] = newbp; // what happens next depends upon what state we are in - switch(this.status()) { + switch (this.status()) { case 'connected': //this._changebpstate([newbp], 'set'); //this._changebpstate([newbp], 'notloaded'); @@ -528,8 +528,8 @@ Debugger.prototype = { } } break; - case 'connecting': - case 'disconnected': + case 'connecting': + case 'disconnected': default: //this._changebpstate([newbp], 'set'); newbp.state = 'set'; @@ -539,25 +539,25 @@ Debugger.prototype = { return newbp; }, - clearbreakpoint : function(srcfpn,line) { + clearbreakpoint: function (srcfpn, line) { var cls = this._splitsrcfpn(srcfpn); - var bp = this.breakpoints.bysrcloc[cls.qtype+':'+line]; + var bp = this.breakpoints.bysrcloc[cls.qtype + ':' + line]; if (!bp) return null; return this._clearbreakpoints([bp])[0]; }, - clearbreakpoints : function(bps) { - if (typeof(bps) === 'function') { + clearbreakpoints: function (bps) { + if (typeof (bps) === 'function') { // argument is a filter function return this.clearbreakpoints(this.getbreakpoints(bps)); } // sanitise first to remove duplicates, non-existants, nulls, etc var bpstoclear = []; var bpkeys = {}; - (bps||[]).forEach(function(bp) { + (bps || []).forEach(function (bp) { if (!bp) return; if (this.breakpoints.all.indexOf(bp) < 0) return; - var bpkey = bp.cls+':'+bp.linenum; + var bpkey = bp.cls + ':' + bp.linenum; if (bpkeys[bpkey]) return; bpkeys[bpkey] = 1; bpstoclear.push(bp); @@ -565,29 +565,29 @@ Debugger.prototype = { return this._clearbreakpoints(bpstoclear); }, - _clearbreakpoints : function(bpstoclear) { + _clearbreakpoints: function (bpstoclear) { if (!bpstoclear || !bpstoclear.length) return []; - bpstoclear.forEach(function(bp) { - delete this.breakpoints.bysrcloc[bp.qtype+':'+bp.linenum]; - this.breakpoints.all.splice(this.breakpoints.all.indexOf(bp),1); + bpstoclear.forEach(function (bp) { + delete this.breakpoints.bysrcloc[bp.qtype + ':' + bp.linenum]; + this.breakpoints.all.splice(this.breakpoints.all.indexOf(bp), 1); }, this); - switch(this.status()) { + switch (this.status()) { case 'connected': - var bpcleareddefs = [{dbgr:this, bpstoclear:bpstoclear}]; + var bpcleareddefs = [{ dbgr: this, bpstoclear: bpstoclear }]; for (var cmlkey in this.breakpoints.enabled) { var enabledbp = this.breakpoints.enabled[cmlkey].bp; - if (bpstoclear.indexOf(enabledbp)>=0) { + if (bpstoclear.indexOf(enabledbp) >= 0) { bpcleareddefs.push(this._clearbreakpointsevent([cmlkey], enabledbp)); } } $.when.apply($, bpcleareddefs) - .then(function(x) { + .then(function (x) { x.dbgr._changebpstate(x.bpstoclear, 'removed'); }); break; - case 'connecting': - case 'disconnected': + case 'connecting': + case 'disconnected': default: this._changebpstate(bpstoclear, 'removed'); break; @@ -596,221 +596,221 @@ Debugger.prototype = { return bpstoclear; }, - getframes : function(threadid, extra) { + getframes: function (threadid, extra) { return this.session.adbclient.jdwp_command({ ths: this, extra: extra, cmd: this.JDWP.Commands.Frames(threadid), - }).then(function(frames, extra) { - var deferreds = [{dbgr:this, frames:frames, threadid:threadid, extra:extra}]; - for (var i=0; i < frames.length; i++) { + }).then(function (frames, extra) { + var deferreds = [{ dbgr: this, frames: frames, threadid: threadid, extra: extra }]; + for (var i = 0; i < frames.length; i++) { deferreds.push(this._findmethodasync(this.session.classes, frames[i].location)); } return $.when.apply($, deferreds) - .then(function(x) { - for (var i=0; i < x.frames.length; i++) { - x.frames[i].method = arguments[i+1][0]; + .then(function (x) { + for (var i = 0; i < x.frames.length; i++) { + x.frames[i].method = arguments[i + 1][0]; x.frames[i].threadid = x.threadid; } - return $.Deferred().resolveWith(x.dbgr, [x.frames,x.extra]); + return $.Deferred().resolveWith(x.dbgr, [x.frames, x.extra]); }); }) }, - getlocals : function(threadid, frame, extra) { + getlocals: function (threadid, frame, extra) { var method = this._findmethod(this.session.classes, frame.location.cid, frame.location.mid); - if (!method) + if (!method) return $.Deferred().resolveWith(this); return this._ensuremethodvars(method) - .then(function(method) { + .then(function (method) { - function withincodebounds(low, length, idx) { - var i=parseInt(low, 16), j=parseInt(idx, 16); - return (j>=i) && (j<(i+length)); - } + function withincodebounds(low, length, idx) { + var i = parseInt(low, 16), j = parseInt(idx, 16); + return (j >= i) && (j < (i + length)); + } - var slots = []; - var validslots = []; - var tags = {'[':76,B:66,C:67,L:76,F:70,D:68,I:73,J:74,S:83,V:86,Z:90}; - for (var i=0, k = method.vartable.vars; i < k.length; i++) { - var tag = tags[k[i].type.signature[0]]; - if (!tag) continue; - var p = { - slot:k[i].slot, - tag:tag, - valid:withincodebounds(k[i].codeidx, k[i].length, frame.location.idx) - }; - slots.push(p); - if (p.valid) validslots.push(p); - } + var slots = []; + var validslots = []; + var tags = { '[': 76, B: 66, C: 67, L: 76, F: 70, D: 68, I: 73, J: 74, S: 83, V: 86, Z: 90 }; + for (var i = 0, k = method.vartable.vars; i < k.length; i++) { + var tag = tags[k[i].type.signature[0]]; + if (!tag) continue; + var p = { + slot: k[i].slot, + tag: tag, + valid: withincodebounds(k[i].codeidx, k[i].length, frame.location.idx) + }; + slots.push(p); + if (p.valid) validslots.push(p); + } - var x = {method:method, extra:extra, slots:slots}; + var x = { method: method, extra: extra, slots: slots }; - if (!validslots.length) { - return $.Deferred().resolveWith(this, [[], x]); - } + if (!validslots.length) { + return $.Deferred().resolveWith(this, [[], x]); + } - return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.GetStackValues(threadid, frame.frameid, validslots), + return this.session.adbclient.jdwp_command({ + ths: this, + extra: x, + cmd: this.JDWP.Commands.GetStackValues(threadid, frame.frameid, validslots), + }); + }) + .then(function (values, x) { + var sv2 = []; + for (var i = 0; i < x.slots.length; i++) { + sv2.push(x.slots[i].valid ? values.shift() : null); + } + return this._mapvalues( + 'local', + x.method.vartable.vars, + sv2, + { frame: frame, slotinfo: null }, + x + ); + }) + .then(function (res, x) { + for (var i = 0; i < res.length; i++) + res[i].data.slotinfo = x.slots[i]; + return $.Deferred().resolveWith(this, [res, x.extra]); }); - }) - .then(function(values, x) { - var sv2 = []; - for (var i=0; i < x.slots.length; i++) { - sv2.push(x.slots[i].valid?values.shift():null); - } - return this._mapvalues( - 'local', - x.method.vartable.vars, - sv2, - {frame: frame, slotinfo:null}, - x - ); - }) - .then(function(res, x) { - for (var i=0; i < res.length; i++) - res[i].data.slotinfo = x.slots[i]; - return $.Deferred().resolveWith(this, [res, x.extra]); - }); }, - setlocalvalue : function(localvar, data, extra) { - return this.ensureconnected({localvar:localvar, data:data, extra:extra}) - .then(function(x) { + setlocalvalue: function (localvar, data, extra) { + return this.ensureconnected({ localvar: localvar, data: data, extra: extra }) + .then(function (x) { return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.SetStackValue(x.localvar.data.frame.threadid, x.localvar.data.frame.frameid, x.localvar.data.slotinfo.slot, x.data), - }); + ths: this, + extra: x, + cmd: this.JDWP.Commands.SetStackValue(x.localvar.data.frame.threadid, x.localvar.data.frame.frameid, x.localvar.data.slotinfo.slot, x.data), + }); }) - .then(function(success, x) { + .then(function (success, x) { return this.session.adbclient.jdwp_command({ ths: this, extra: x, cmd: this.JDWP.Commands.GetStackValues(x.localvar.data.frame.threadid, x.localvar.data.frame.frameid, [x.localvar.data.slotinfo]), }); }) - .then(function(stackvalues, x) { + .then(function (stackvalues, x) { return this._mapvalues( 'local', - [x.localvar], - stackvalues, + [x.localvar], + stackvalues, x.localvar.data, x ); }) - .then(function(res, x) { + .then(function (res, x) { return $.Deferred().resolveWith(this, [res[0], x.extra]); }); }, - getsupertype : function(local, extra) { - return this.gettypedebuginfo(local.type.signature, {local:local, extra:extra}) - .then(function(dbgtype, x) { + getsupertype: function (local, extra) { + return this.gettypedebuginfo(local.type.signature, { local: local, extra: extra }) + .then(function (dbgtype, x) { return this._ensuresuper(dbgtype[x.local.type.signature]) }) - .then(function(typeinfo) { + .then(function (typeinfo) { return $.Deferred().resolveWith(this, [typeinfo.super, extra]); }); }, - createstring : function(string, extra) { - return this.ensureconnected({string:string, extra:extra}) - .then(function(x) { + createstring: function (string, extra) { + return this.ensureconnected({ string: string, extra: extra }) + .then(function (x) { return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.CreateStringObject(string), - }); + ths: this, + extra: x, + cmd: this.JDWP.Commands.CreateStringObject(string), + }); }) - .then(function(strobjref, x) { - var keys = [{name:'', type:this.JDWP.signaturetotype('Ljava/lang/String;')}]; + .then(function (strobjref, x) { + var keys = [{ name: '', type: this.JDWP.signaturetotype('Ljava/lang/String;') }]; return this._mapvalues('literal', keys, [strobjref], null, x); }) - .then(function(vars, x) { + .then(function (vars, x) { return $.Deferred().resolveWith(this, [vars[0], x.extra]); }); }, - setstringvalue : function(variable, string, extra) { - return this.createstring(string, {variable:variable, extra:extra}) - .then(function(string_variable, x) { + setstringvalue: function (variable, string, extra) { + return this.createstring(string, { variable: variable, extra: extra }) + .then(function (string_variable, x) { var value = { - value:string_variable.value, - valuetype:'oref', + value: string_variable.value, + valuetype: 'oref', }; return this.setvalue(x.variable, value, x.extra); }) }, - setvalue : function(variable, data, extra) { + setvalue: function (variable, data, extra) { if (data.stringliteral) { return this.setstringvalue(variable, data.value, extra); } - switch(variable.vtype) { + switch (variable.vtype) { case 'field': return this.setfieldvalue(variable, data, extra); case 'local': return this.setlocalvalue(variable, data, extra); - case 'arrelem': + case 'arrelem': return this.setarrayvalues(variable.data.arrobj, parseInt(variable.name), 1, data, extra) - .then(function(res, extra) { + .then(function (res, extra) { // setarrayvalues returns an array of updated elements - just return the one return $.Deferred().resolveWith(this, [res[0], extra]); }); } }, - setfieldvalue : function(fieldvar, data, extra) { - return this.ensureconnected({fieldvar:fieldvar, data:data, extra:extra}) - .then(function(x) { + setfieldvalue: function (fieldvar, data, extra) { + return this.ensureconnected({ fieldvar: fieldvar, data: data, extra: extra }) + .then(function (x) { return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.SetFieldValue(x.fieldvar.data.objvar.value, x.fieldvar.data.field, x.data), - }); + ths: this, + extra: x, + cmd: this.JDWP.Commands.SetFieldValue(x.fieldvar.data.objvar.value, x.fieldvar.data.field, x.data), + }); }) - .then(function(success, x) { + .then(function (success, x) { return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.GetFieldValues(x.fieldvar.data.objvar.value, [x.fieldvar.data.field]), - }); + ths: this, + extra: x, + cmd: this.JDWP.Commands.GetFieldValues(x.fieldvar.data.objvar.value, [x.fieldvar.data.field]), + }); }) - .then(function(fieldvalues, x) { + .then(function (fieldvalues, x) { return this._mapvalues('field', [x.fieldvar.data.field], fieldvalues, x.fieldvar.data, x); }) - .then(function(data, x) { + .then(function (data, x) { return $.Deferred().resolveWith(this, [data[0], x.extra]); }); }, - getfieldvalues : function(objvar, extra) { - return this.gettypedebuginfo(objvar.type.signature, {objvar:objvar, extra:extra}) - .then(function(dbgtype, x) { + getfieldvalues: function (objvar, extra) { + return this.gettypedebuginfo(objvar.type.signature, { objvar: objvar, extra: extra }) + .then(function (dbgtype, x) { return this._ensurefields(dbgtype[x.objvar.type.signature], x); }) - .then(function(typeinfo, x) { + .then(function (typeinfo, x) { x.typeinfo = typeinfo; return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.GetFieldValues(x.objvar.value, typeinfo.fields), - }); + ths: this, + extra: x, + cmd: this.JDWP.Commands.GetFieldValues(x.objvar.value, typeinfo.fields), + }); }) - .then(function(fieldvalues, x) { - return this._mapvalues('field', x.typeinfo.fields, fieldvalues, {objvar:x.objvar}, x); + .then(function (fieldvalues, x) { + return this._mapvalues('field', x.typeinfo.fields, fieldvalues, { objvar: x.objvar }, x); }) - .then(function(res, x) { - for (var i=0; i < res.length; i++) { + .then(function (res, x) { + for (var i = 0; i < res.length; i++) { res[i].data.field = x.typeinfo.fields[i]; } return $.Deferred().resolveWith(this, [res, x.extra]); }); }, - getstringchars : function(stringref, extra) { + getstringchars: function (stringref, extra) { return this.session.adbclient.jdwp_command({ ths: this, extra: extra, @@ -818,79 +818,79 @@ Debugger.prototype = { }); }, - _getstringlen : function(stringref, extra) { - return this.gettypedebuginfo('Ljava/lang/String;', {stringref:stringref, extra:extra}) - .then(function(dbgtype, x) { + _getstringlen: function (stringref, extra) { + return this.gettypedebuginfo('Ljava/lang/String;', { stringref: stringref, extra: extra }) + .then(function (dbgtype, x) { return this._ensurefields(dbgtype['Ljava/lang/String;'], x); }) - .then(function(typeinfo, x) { - var countfields = typeinfo.fields.filter(f => f.name==='count'); + .then(function (typeinfo, x) { + var countfields = typeinfo.fields.filter(f => f.name === 'count'); if (!countfields.length) return -1; return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.GetFieldValues(x.stringref, countfields), - }); + ths: this, + extra: x, + cmd: this.JDWP.Commands.GetFieldValues(x.stringref, countfields), + }); }) - .then(function(countfields, x) { - var len = (countfields && countfields.length===1) ? countfields[0] : -1; + .then(function (countfields, x) { + var len = (countfields && countfields.length === 1) ? countfields[0] : -1; return $.Deferred().resolveWith(this, [len, x.extra]); }); }, - getarrayvalues : function(local, start, count, extra) { - return this.gettypedebuginfo(local.type.elementtype.signature, {local:local, start:start, count:count, extra:extra}) - .then(function(dbgtype, x) { + getarrayvalues: function (local, start, count, extra) { + return this.gettypedebuginfo(local.type.elementtype.signature, { local: local, start: start, count: count, extra: extra }) + .then(function (dbgtype, x) { x.type = dbgtype[x.local.type.elementtype.signature].type; return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.GetArrayValues(x.local.value, x.start, x.count), + ths: this, + extra: x, + cmd: this.JDWP.Commands.GetArrayValues(x.local.value, x.start, x.count), }); }) - .then(function(values, x) { + .then(function (values, x) { // generate some dummy keys to map against var keys = []; - for (var i=0; i < x.count; i++) { - keys.push({name:''+(x.start+i), type:x.type}); + for (var i = 0; i < x.count; i++) { + keys.push({ name: '' + (x.start + i), type: x.type }); } - return this._mapvalues('arrelem', keys, values, {arrobj:x.local}, x.extra); + return this._mapvalues('arrelem', keys, values, { arrobj: x.local }, x.extra); }); }, - setarrayvalues : function(arrvar, start, count, data, extra) { - return this.ensureconnected({arrvar:arrvar, start:start, count:count, data:data, extra:extra}) - .then(function(x) { + setarrayvalues: function (arrvar, start, count, data, extra) { + return this.ensureconnected({ arrvar: arrvar, start: start, count: count, data: data, extra: extra }) + .then(function (x) { return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.SetArrayElements(x.arrvar.value, x.start, x.count, x.data), - }); + ths: this, + extra: x, + cmd: this.JDWP.Commands.SetArrayElements(x.arrvar.value, x.start, x.count, x.data), + }); }) - .then(function(success, x) { + .then(function (success, x) { return this.session.adbclient.jdwp_command({ - ths: this, - extra: x, - cmd: this.JDWP.Commands.GetArrayValues(x.arrvar.value, x.start, x.count), - }); + ths: this, + extra: x, + cmd: this.JDWP.Commands.GetArrayValues(x.arrvar.value, x.start, x.count), + }); }) - .then(function(values, x) { + .then(function (values, x) { // generate some dummy keys to map against var keys = []; - for (var i=0; i < count; i++) { - keys.push({name:''+(x.start+i), type:x.arrvar.type.elementtype}); + for (var i = 0; i < count; i++) { + keys.push({ name: '' + (x.start + i), type: x.arrvar.type.elementtype }); } - return this._mapvalues('arrelem', keys, values, {arrobj:x.arrvar}, x.extra); + return this._mapvalues('arrelem', keys, values, { arrobj: x.arrvar }, x.extra); }); }, - _mapvalues : function(vtype, keys, values, data, extra) { + _mapvalues: function (vtype, keys, values, data, extra) { var res = []; var arrayfields = []; var stringfields = []; if (values && Array.isArray(values)) { - var v = values.slice(0), i=0; + var v = values.slice(0), i = 0; while (v.length) { var info = { vtype: vtype, @@ -899,28 +899,28 @@ Debugger.prototype = { type: keys[i].type, hasnullvalue: false, valid: true, - data:Object.assign({},data), + data: Object.assign({}, data), }; info.hasnullvalue = /^0+$/.test(info.value); - info.valid = info.value!==null; + info.valid = info.value !== null; res.push(info); if (keys[i].type.arraydims) arrayfields.push(info); - else if (keys[i].type.signature==='Ljava/lang/String;') + else if (keys[i].type.signature === 'Ljava/lang/String;') stringfields.push(info); i++; } } - var defs = [{dbgr:this, res:res, extra:extra}]; + var defs = [{ dbgr: this, res: res, extra: extra }]; // for those fields that are (non-null) arrays, retrieve the length for (var i in arrayfields) { if (arrayfields[i].hasnullvalue || !arrayfields[i].valid) continue; var def = this.session.adbclient.jdwp_command({ - ths: this, - extra: arrayfields[i], - cmd: this.JDWP.Commands.GetArrayLength(arrayfields[i].value), - }) - .then(function(arrlen, arrfield) { + ths: this, + extra: arrayfields[i], + cmd: this.JDWP.Commands.GetArrayLength(arrayfields[i].value), + }) + .then(function (arrlen, arrfield) { arrfield.arraylen = arrlen; }); defs.push(def); @@ -929,14 +929,14 @@ Debugger.prototype = { for (var i in stringfields) { if (stringfields[i].hasnullvalue || !stringfields[i].valid) continue; var def = this._getstringlen(stringfields[i].value) - .then(function(len) { + .then(function (len) { if (len > 10000) return $.Deferred().resolveWith(this, [len, stringfields[i]]); // retrieve the actual chars return this.getstringchars(stringfields[i].value, stringfields[i]); }) - .then(function(str, strfield) { - if (typeof(str)==='number') { + .then(function (str, strfield) { + if (typeof (str) === 'number') { strfield.string = '{string exceeds maximum display length}'; strfield.biglen = str; } else { @@ -947,17 +947,17 @@ Debugger.prototype = { } return $.when.apply($, defs) - .then(function(x) { + .then(function (x) { return $.Deferred().resolveWith(x.dbgr, [x.res, x.extra]); }); }, - gettypedebuginfo : function(signature, extra) { + gettypedebuginfo: function (signature, extra) { var info = { - signature:signature, - classes:{}, - ci:{ type: this.JDWP.signaturetotype(signature), }, + signature: signature, + classes: {}, + ci: { type: this.JDWP.signaturetotype(signature), }, extra: extra, deferred: $.Deferred(), }; @@ -979,14 +979,14 @@ Debugger.prototype = { } this.ensureconnected(info) - .then(function(info) { + .then(function (info) { return this.session.adbclient.jdwp_command({ - ths: this, - extra: info, - cmd: this.JDWP.Commands.classinfo(info.ci), - }); + ths: this, + extra: info, + cmd: this.JDWP.Commands.classinfo(info.ci), + }); }) - .then(function(classinfoarr, info) { + .then(function (classinfoarr, info) { if (!classinfoarr || !classinfoarr.length) { if (this.session) delete this.session.classes[info.signature]; @@ -997,14 +997,14 @@ Debugger.prototype = { info.classes[info.ci.type.signature] = info.ci; // querying the source file for array or primitive types causes the app to crash - return (info.ci.type.signature[0]!=='L' + return (info.ci.type.signature[0] !== 'L' ? $.Deferred().resolveWith(this, [[null], info]) : this.session.adbclient.jdwp_command({ ths: this, extra: info, cmd: this.JDWP.Commands.sourcefile(info.ci), })) - .then(function(srcinfoarr, info) { + .then(function (srcinfoarr, info) { info.ci.src = srcinfoarr[0]; if (this.session) { Object.assign(this.session.classes, info.classes); @@ -1016,40 +1016,40 @@ Debugger.prototype = { return info.deferred; }, - _ensuresuper : function(typeinfo) { - if (typeinfo.super||typeinfo.super===null) { + _ensuresuper: function (typeinfo) { + if (typeinfo.super || typeinfo.super === null) { if (typeinfo.super && typeinfo.super.promise) return typeinfo.super.promise(); return $.Deferred().resolveWith(this, [typeinfo]); } - if (typeinfo.info.reftype.string!=='class'||typeinfo.type.signature[0]!=='L'||typeinfo.type.signature==='Ljava/lang/Object;') { - typeinfo.super=null; + if (typeinfo.info.reftype.string !== 'class' || typeinfo.type.signature[0] !== 'L' || typeinfo.type.signature === 'Ljava/lang/Object;') { + typeinfo.super = null; return $.Deferred().resolveWith(this, [typeinfo]); } typeinfo.super = $.Deferred(); this.session.adbclient.jdwp_command({ - ths: this, - extra: typeinfo, - cmd: this.JDWP.Commands.superclass(typeinfo), - }) - .then(function(superclassref, typeinfo) { + ths: this, + extra: typeinfo, + cmd: this.JDWP.Commands.superclass(typeinfo), + }) + .then(function (superclassref, typeinfo) { return this.session.adbclient.jdwp_command({ ths: this, extra: typeinfo, cmd: this.JDWP.Commands.signature(superclassref), }); }) - .then(function(supertype, typeinfo) { + .then(function (supertype, typeinfo) { var def = typeinfo.super; - typeinfo.super=supertype; + typeinfo.super = supertype; def.resolveWith(this, [typeinfo]); }); return typeinfo.super.promise(); }, - _ensurefields : function(typeinfo, extra) { + _ensurefields: function (typeinfo, extra) { if (typeinfo.fields) { if (typeinfo.fields.promise) return typeinfo.fields.promise(); @@ -1058,11 +1058,11 @@ Debugger.prototype = { typeinfo.fields = $.Deferred(); this.session.adbclient.jdwp_command({ - ths: this, - extra: {typeinfo:typeinfo, extra:extra} , - cmd: this.JDWP.Commands.fieldsWithGeneric(typeinfo), - }) - .then(function(fields, x) { + ths: this, + extra: { typeinfo: typeinfo, extra: extra }, + cmd: this.JDWP.Commands.fieldsWithGeneric(typeinfo), + }) + .then(function (fields, x) { var def = x.typeinfo.fields; x.typeinfo.fields = fields; def.resolveWith(this, [x.typeinfo, x.extra]); @@ -1071,7 +1071,7 @@ Debugger.prototype = { return typeinfo.fields.promise(); }, - _ensuremethods : function(typeinfo) { + _ensuremethods: function (typeinfo) { if (typeinfo.methods) { if (typeinfo.methods.promise) return typeinfo.methods.promise(); @@ -1080,11 +1080,11 @@ Debugger.prototype = { typeinfo.methods = $.Deferred(); this.session.adbclient.jdwp_command({ - ths: this, - extra: typeinfo, - cmd: this.JDWP.Commands.methodsWithGeneric(typeinfo), - }) - .then(function(methods, typeinfo) { + ths: this, + extra: typeinfo, + cmd: this.JDWP.Commands.methodsWithGeneric(typeinfo), + }) + .then(function (methods, typeinfo) { var def = typeinfo.methods; typeinfo.methods = {}; for (var i in methods) { @@ -1097,7 +1097,7 @@ Debugger.prototype = { return typeinfo.methods.promise(); }, - _ensuremethodvars : function(methodinfo) { + _ensuremethodvars: function (methodinfo) { if (methodinfo.vartable) { if (methodinfo.vartable.promise) return methodinfo.vartable.promise(); @@ -1106,11 +1106,11 @@ Debugger.prototype = { methodinfo.vartable = $.Deferred(); this.session.adbclient.jdwp_command({ - ths: this, - extra: methodinfo, - cmd: this.JDWP.Commands.VariableTableWithGeneric(methodinfo.owningclass, methodinfo), - }) - .then(function(vartable, methodinfo) { + ths: this, + extra: methodinfo, + cmd: this.JDWP.Commands.VariableTableWithGeneric(methodinfo.owningclass, methodinfo), + }) + .then(function (vartable, methodinfo) { var def = methodinfo.vartable; methodinfo.vartable = vartable; def.resolveWith(this, [methodinfo]); @@ -1119,7 +1119,7 @@ Debugger.prototype = { return methodinfo.vartable.promise(); }, - _ensuremethodlines : function(methodinfo) { + _ensuremethodlines: function (methodinfo) { if (methodinfo.linetable) { if (methodinfo.linetable.promise) return methodinfo.linetable.promise(); @@ -1128,15 +1128,15 @@ Debugger.prototype = { methodinfo.linetable = $.Deferred(); this.session.adbclient.jdwp_command({ - ths: this, - extra: methodinfo, - cmd: this.JDWP.Commands.lineTable(methodinfo.owningclass, methodinfo), - }) - .then(function(linetable, methodinfo) { + ths: this, + extra: methodinfo, + cmd: this.JDWP.Commands.lineTable(methodinfo.owningclass, methodinfo), + }) + .then(function (linetable, methodinfo) { // the linetable does not correlate code indexes with line numbers // - location searching relies on the table being ordered by code indexes - linetable.lines.sort(function(a,b){ - return (a.linecodeidx===b.linecodeidx)?0:((a.linecodeidx idx) - k=prevk; + k = prevk; // convert the class signature to a file location var m = method.owningclass.type.signature.match(/^L([^;$]+)[$a-zA-Z0-9_]*;$/); - if (!m) + if (!m) return null; return { - qtype:m[1], - linenum:lines[k].linenum, + qtype: m[1], + linenum: lines[k].linenum, }; } return null; }, - _findcmllocation : function(classes, loc) { + _findcmllocation: function (classes, loc) { // search the classes for a method containing the line return this._findmethodasync(classes, loc) - .then(function(method) { + .then(function (method) { if (!method) return $.Deferred().resolveWith(this, [null]); return this._ensuremethodlines(method) - .then(function(method) { + .then(function (method) { var srcloc = this.line_idx_to_source_location(method, loc.idx); return $.Deferred().resolveWith(this, [srcloc]); }); }); }, - _findmethodasync : function(classes, location) { + _findmethodasync: function (classes, location) { var m = this._findmethod(classes, location.cid, location.mid); if (m) return $.Deferred().resolveWith(this, [m]); // convert the classid to a type signature return this.session.adbclient.jdwp_command({ - ths:this, - extra:{location:location}, - cmd: this.JDWP.Commands.signature(location.cid), - }) - .then(function(type, x) { + ths: this, + extra: { location: location }, + cmd: this.JDWP.Commands.signature(location.cid), + }) + .then(function (type, x) { return this.gettypedebuginfo(type.signature, x); }) - .then(function(classes, x) { - var defs = [{dbgr:this, classes:classes, x:x}]; - for(var clz in classes) { + .then(function (classes, x) { + var defs = [{ dbgr: this, classes: classes, x: x }]; + for (var clz in classes) { defs.push(this._ensuremethods(classes[clz])); } - return $.when.apply($, defs).then(function(x) { + return $.when.apply($, defs).then(function (x) { return $.Deferred().resolveWith(x.dbgr, [x.classes, x.x]); }) }) - .then(function(classes, x) { + .then(function (classes, x) { var m = this._findmethod(classes, x.location.cid, x.location.mid); return $.Deferred().resolveWith(this, [m]); }); }, - _findmethod : function(classes, classid, methodid) { + _findmethod: function (classes, classid, methodid) { for (var i in classes) { if (classes[i]._isdeferred) continue; @@ -1470,7 +1470,7 @@ Debugger.prototype = { return null; }, - _finitbreakpoints : function() { + _finitbreakpoints: function () { this._changebpstate(this.breakpoints.all, 'set'); this.breakpoints.enabled = {}; },