const $ = require('./jq-promise'); const { atob,btoa,D,getutf8bytes,fromutf8bytes,intToHex } = require('./util'); /* JDWP - The Java Debug Wire Protocol */ function _JDWP() { var gCommandId = 0; var gCommandList = []; var gEventCallbacks = {}; function Command(name, cs, cmd, outdatafn, replydecodefn) { this.length = 11; this.id = ++gCommandId; this.flags = 0; this.commandset = cs; this.command = cmd; this.rawdata = outdatafn?outdatafn():[]; this.length = 11 + this.rawdata.length; gCommandList[this.id] = this; this.name = name; this.replydecodefn = replydecodefn; this.deferred = $.Deferred(); } Command.prototype = { promise : function() { return this.deferred.promise(); }, toRawString : function() { var s = ''; s += String.fromCharCode((this.length >> 24)&255); s += String.fromCharCode((this.length >> 16)&255); s += String.fromCharCode((this.length >> 8)&255); s += String.fromCharCode((this.length)&255); s += String.fromCharCode((this.id >> 24)&255); s += String.fromCharCode((this.id >> 16)&255); s += String.fromCharCode((this.id >> 8)&255); s += String.fromCharCode((this.id)&255); s += String.fromCharCode(this.flags); s += String.fromCharCode(this.commandset); s += String.fromCharCode(this.command); var i=this.rawdata.length, j=0; while (--i>=0) { s += String.fromCharCode(this.rawdata[j++]); } return s; }, tob64 : function() { return btoa(this.toRawString()); } }; function Reply(s) { this.length = s.charCodeAt(0) << 24; this.length += s.charCodeAt(1) << 16; this.length += s.charCodeAt(2) << 8; this.length += s.charCodeAt(3); this.id = s.charCodeAt(4) << 24; this.id += s.charCodeAt(5) << 16; this.id += s.charCodeAt(6) << 8; this.id += s.charCodeAt(7); this.flags = s.charCodeAt(8)|0; this.errorcode = s.charCodeAt(9) << 8; this.errorcode += s.charCodeAt(10); this.rawdata = new Array(s.length-11); var i=0, j=this.rawdata.length; while (--j>=0) { this.rawdata[i]=s.charCodeAt(i+11); i++; } this.command = gCommandList[this.id]; if (this.errorcode===16484) { // errorcode===16484 (0x4064) means a composite event command (set 64,cmd 100) sent from the VM this.errorcode=0; this.isevent=!0; this.decoded=DataCoder.decodeCompositeEvent({ idx:0, data:this.rawdata.slice() }); // call any registered event callbacks for (var i in this.decoded.events) { var event = this.decoded.events[i]; var cbinfo = event.reqid && gEventCallbacks[event.reqid]; if (cbinfo) { var e = { data:cbinfo.callback.data, event:event, reply:this, }; cbinfo.callback.fn.call(cbinfo.callback.ths, e); } } return; } if (this.errorcode != 0) { console.error("Command failed: error " + this.errorcode); } if (!this.errorcode && this.command && this.command.replydecodefn) { // try and decode the values this.decoded = this.command.replydecodefn({ idx:0, data:this.rawdata.slice() }); return; } this.decoded = {empty:true}; } this.decodereply = function(ths,s) { var reply = new Reply(s); if (reply.command) { reply.command.deferred.resolveWith(ths, [reply.decoded, reply.command, reply]); } return reply; }; this.signaturetotype = function(s) { return DataCoder.signaturetotype(s); } this.setIDSizes = function(idsizes) { DataCoder._idsizes = idsizes; } var DataCoder = { _idsizes:null, decodeString: function(o) { var rd = o.data; var utf8len=(rd[o.idx++]<<24)+(rd[o.idx++]<<16)+(rd[o.idx++]<<8)+(rd[o.idx++]); if (utf8len > 10000) utf8len = 10000; // just to prevent hangs if the decoding is wrong var res=fromutf8bytes(o.data.slice(o.idx, o.idx+utf8len)); o.idx+= utf8len; return res; }, decodeLong: function(o, hexstring) { var rd = o.data; var res1=(rd[o.idx++]<<24)+(rd[o.idx++]<<16)+(rd[o.idx++]<<8)+(rd[o.idx++]); var res2=(rd[o.idx++]<<24)+(rd[o.idx++]<<16)+(rd[o.idx++]<<8)+(rd[o.idx++]); return intToHex(res1,8)+intToHex(res2,8); }, decodeInt: function(o) { var rd = o.data; var res=(rd[o.idx++]<<24)+(rd[o.idx++]<<16)+(rd[o.idx++]<<8)+(rd[o.idx++]); return res; }, decodeByte: function(o) { var i = o.data[o.idx++]; return i<128?i:i-256; }, decodeShort: function(o) { var i = (o.data[o.idx++]<<8)+o.data[o.idx++]; return i<32768?i:i-65536; }, decodeChar: function(o) { return String.fromCharCode((o.data[o.idx++]<<8)+o.data[o.idx++]); }, decodeBoolean: function(o) { return o.data[o.idx++] != 0; }, decodeDecimal: function(bytes, signBits, exponentBits, fractionBits, eMin, eMax, littleEndian) { var totalBits = (signBits + exponentBits + fractionBits); var binary = ""; for (var i = 0, l = bytes.length; i < l; i++) { var bits = bytes[i].toString(2); while (bits.length < 8) bits = "0" + bits; if (littleEndian) binary = bits + binary; else binary += bits; } var sign = (binary.charAt(0) == '1')?-1:1; var exponent = parseInt(binary.substr(signBits, exponentBits), 2) - eMax; var significandBase = binary.substr(signBits + exponentBits, fractionBits); var significandBin = '1'+significandBase; var i = 0; var val = 1; var significand = 0; if (exponent+eMax===((eMax*2)+1)) { if (significandBase.indexOf('1')<0) return sign>0?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY; return Number.NaN; } if (exponent == -eMax) { if (significandBase.indexOf('1') == -1) return 0; else { exponent = eMin; significandBin = '0'+significandBase; } } while (i < significandBin.length) { significand += val * parseInt(significandBin.charAt(i)); val = val / 2; i++; } return sign * significand * Math.pow(2, exponent); }, decodeFloat: function(o) { var bytes = o.data.slice(o.idx, o.idx+=4); return this.decodeDecimal(bytes, 1, 8, 23, -126, 127, false); }, decodeDouble: function(o) { var bytes = o.data.slice(o.idx, o.idx+=8); return this.decodeDecimal(bytes, 1, 11, 52, -1022, 1023, false); }, decodeRef: function(o, bytes) { var rd = o.data; var res = ''; while (--bytes>=0) { res += ('0'+rd[o.idx++].toString(16)).slice(-2); } return res; }, decodeTRef: function(o) { return this.decodeRef(o,this._idsizes.reftypeidsize); }, decodeORef: function(o) { return this.decodeRef(o,this._idsizes.objectidsize); }, decodeMRef: function(o) { return this.decodeRef(o,this._idsizes.methodidsize); }, decodeRefType : function(o) { return this.mapvalue(this.decodeByte(o), [null,'class','interface','array']); }, decodeStatus : function(o) { return this.mapflags(this.decodeInt(o), ['verified','prepared','initialized','error']); }, decodeValue : function(o) { var rd = o.data; return this.tagtodecoder(rd[o.idx++]).call(this, o); }, tagtodecoder: function(tag) { switch (tag) { case 91: case 76: case 115: case 116: case 103: case 108: case 99: return this.decodeORef; case 66: return this.decodeByte; case 90: return this.decodeBoolean; case 67: return this.decodeChar; case 83: return this.decodeShort; case 70: return this.decodeFloat; case 73: return this.decodeInt; case 68: return this.decodeDouble; case 74: return this.decodeLong; case 86: return function() { return 'void'; }; } }, mapvalue : function(value,values) { return {value: value, string:values[value] }; }, mapflags : function(value,values) { var res = {value: value, string:'[]'}; var flgs=[]; for (var i=value,j=0;i;i>>=1) { if ((i&1)&&(values[j])) flgs.push(values[j]); j++; } res.string = '['+flgs.join('|')+']'; return res; }, decodeList: function(o, list) { var res = {}; while (list.length) { var next = list.shift(); for ( var key in next) { switch(next[key]) { case 'string': res[key]=this.decodeString(o); break; case 'int': res[key]=this.decodeInt(o); break; case 'long': res[key]=this.decodeLong(o); break; case 'byte': res[key]=this.decodeByte(o); break; case 'fref': res[key]=this.decodeRef(o,this._idsizes.fieldidsize); break; case 'mref': res[key]=this.decodeRef(o,this._idsizes.methodidsize); break; case 'oref': res[key]=this.decodeRef(o,this._idsizes.objectidsize); break; case 'tref': res[key]=this.decodeRef(o,this._idsizes.reftypeidsize); break; case 'frameid': res[key]=this.decodeRef(o,this._idsizes.frameidsize); break; case 'reftype': res[key]=this.decodeRefType(o); break; case 'status': res[key]=this.decodeStatus(o); break; case 'location': res[key]=this.decodeLocation(o); break; case 'signature': res[key]=this.decodeTypeFromSignature(o); break; case 'codeindex': res[key]=this.decodeLong(o, true); break; } } } return res; }, decodeLocation : function(o) { return { type: o.data[o.idx++], cid: this.decodeTRef(o), mid: this.decodeMRef(o), idx: this.decodeLong(o, true), }; }, decodeTypeFromSignature : function(o) { var sig = this.decodeString(o); return this.signaturetotype(sig); }, decodeCompositeEvent: function (o) { var rd = o.data; var res = {}; res.suspend = rd[o.idx++]; res.events = []; var arrlen = this.decodeInt(o); while (--arrlen>=0) { // all event types return kind+requestid as their first entries var event = { kind:{name:'', value:rd[o.idx++]}, }; var eventkinds = ['','step','breakpoint','framepop','exception','userdefined','threadstart','threadend','classprepare','classunload','classload']; event.kind.name = eventkinds[event.kind.value]; switch(event.kind.value) { case 1: // step case 2: // breakpoint event.reqid = this.decodeInt(o); event.threadid = this.decodeORef(o); event.location = this.decodeLocation(o); break; case 8: // classprepare event.reqid = this.decodeInt(o); event.threadid = this.decodeORef(o); event.reftype = this.decodeByte(o); event.typeid = this.decodeTRef(o); event.type = this.decodeTypeFromSignature(o); event.status = this.decodeStatus(o); break; } res.events.push(event); } return res; }, encodeByte : function(res, i) { res.push(i&255); }, encodeBoolean : function(res, b) { res.push(b?1:0); }, encodeShort : function(res, i) { res.push((i>>8)&255); res.push((i)&255); }, encodeInt : function(res, i) { res.push((i>>24)&255); res.push((i>>16)&255); res.push((i>>8)&255); res.push((i)&255); }, encodeChar: function(res, c) { this.encodeShort(res, c.charCodeAt(0)); }, encodeString : function(res, s) { var utf8bytes = getutf8bytes(s); this.encodeInt(res, utf8bytes.length); for (var i=0; i < utf8bytes.length; i++) res.push(utf8bytes[i]); }, encodeRef: function(res, ref) { for(var i=0; i < ref.length; i+=2) { res.push(parseInt(ref.substring(i,i+2), 16)); } }, encodeLong: function(res, l) { for(var i=0; i < l.length; i+=2) { res.push(parseInt(l.substring(i,i+2), 16)); } }, encodeDouble: function(res, value) { var hiWord = 0, loWord = 0; switch (value) { case Number.POSITIVE_INFINITY: hiWord = 0x7FF00000; break; case Number.NEGATIVE_INFINITY: hiWord = 0xFFF00000; break; case +0.0: hiWord = 0x00000000; break;//0x40000000; break; case -0.0: hiWord = 0x80000000; break;//0xC0000000; break; default: if (Number.isNaN(value)) { hiWord = 0x7FF80000; break; } if (value <= -0.0) { hiWord = 0x80000000; value = -value; } var exponent = Math.floor(Math.log(value) / Math.log(2)); var significand = Math.floor((value / Math.pow(2, exponent)) * Math.pow(2, 52)); loWord = significand & 0xFFFFFFFF; significand /= Math.pow(2, 32); exponent += 1023; if (exponent >= 0x7FF) { exponent = 0x7FF; significand = 0; } else if (exponent < 0) exponent = 0; hiWord = hiWord | (exponent << 20); hiWord = hiWord | (significand & ~(-1 << 20)); break; } this.encodeInt(res, hiWord); this.encodeInt(res, loWord); }, encodeFloat: function(res, value) { var bytes = 0; switch (value) { case Number.POSITIVE_INFINITY: bytes = 0x7F800000; break; case Number.NEGATIVE_INFINITY: bytes = 0xFF800000; break; case +0.0: bytes = 0x00000000; break;//0x40000000; break; case -0.0: bytes = 0x80000000; break;//0xC0000000l default: if (Number.isNaN(value)) { bytes = 0x7FC00000; break; } if (value <= -0.0) { bytes = 0x80000000; value = -value; } var exponent = Math.floor(Math.log(value) / Math.log(2)); var significand = ((value / Math.pow(2, exponent)) * 0x00800000) | 0; exponent += 127; if (exponent >= 0xFF) { exponent = 0xFF; significand = 0; } else if (exponent < 0) exponent = 0; bytes = bytes | (exponent << 23); bytes = bytes | (significand & ~(-1 << 23)); break; } this.encodeInt(res, bytes); }, encodeValue: function(res, key, data) { switch(key) { case 'byte': this.encodeByte(res, data); break; case 'short': this.encodeShort(res, data); break; case 'int': this.encodeInt(res, data); break; case 'long': this.encodeLong(res, data); break; case 'boolean': this.encodeBoolean(res, data); break; case 'char': this.encodeChar(res, data); break; case 'float': this.encodeFloat(res, data); break; case 'double': this.encodeDouble(res, data); break; // note that strings are encoded as object references... case 'oref': this.encodeRef(res,data); break; } }, encodeTaggedValue: function(res, key, data) { switch(key) { case 'byte': res.push(66); break; case 'short': res.push(83); break; case 'int': res.push(73); break; case 'long': res.push(74); break; case 'boolean': res.push(90); break; case 'char': res.push(67); break; case 'float': res.push(70); break; case 'double': res.push(68); break; case 'void': res.push(86); break; // note that strings are encoded as object references... case 'oref': res.push(76); break; } this.encodeValue(res, key, data); }, signaturetotype:function(signature) { var m = signature.match(/^L([^$]+)\/([^$\/]+)(\$.+)?;$/); if (m) { return { signature: signature, package: m[1].replace(/\//g,'.'), typename: (m[2]+(m[3]||'')).replace(/\$(?=[^\d])/g,'.'), anonymous: /\$\d/.test(m[3]), } } m = signature.match(/^(\[+)(.+)$/); if (m) { var elementtype = this.signaturetotype(m[2]); return { signature:signature, arraydims:m[1].length, elementtype: elementtype, typename:elementtype.typename+m[1].replace(/\[/g,'[]'), } } var primitivetypes = { B: { signature:'B', typename:'byte', primitive:true, }, C: { signature:'C', typename:'char', primitive:true, }, F: { signature:'F', typename:'float', primitive:true, }, D: { signature:'D', typename:'double', primitive:true, }, I: { signature:'I', typename:'int', primitive:true, }, J: { signature:'J', typename:'long', primitive:true, }, S: { signature:'S', typename:'short', primitive:true, }, V: { signature:'V', typename:'void', primitive:true, }, Z: { signature:'Z', typename:'boolean', primitive:true, }, } var res = (signature.length===1)?primitivetypes[signature[0]]:null; if (res) return res; return { signature:signature, typename:signature, invalid:true, } }, }; //var Commands = { this.Commands = { version:function() { return new Command('version',1, 1, null, function (o) { return DataCoder.decodeList(o, [{description:'string'},{major:'int'},{minor:'int'},{version:'string'},{name:'string'}]); } ); }, idsizes:function() { return new Command('IDSizes', 1, 7, function() { return []; }, function(o) { return DataCoder.decodeList(o, [{fieldidsize:'int'},{methodidsize:'int'},{objectidsize:'int'},{reftypeidsize:'int'},{frameidsize:'int'}]); } ); }, classinfo:function(ci) { return new Command('ClassesBySignature:'+ci.name, 1, 2, function() { var res=[]; DataCoder.encodeString(res, ci.type.signature); return res; }, function(o) { var arrlen = DataCoder.decodeInt(o); var res = []; while (--arrlen>=0) { res.push(DataCoder.decodeList(o, [{reftype:'reftype'},{typeid:'tref'},{status:'status'}])); } return res; } ); }, fields:function(ci) { // not supported by Dalvik return new Command('Fields:'+ci.name, 2, 4, function() { var res=[]; DataCoder.encodeRef(res, ci.info.typeid); return res; }, function(o) { var arrlen = DataCoder.decodeInt(o); var res = []; while (--arrlen>=0) { res.push(DataCoder.decodeList(o, [{fieldid:'fref'},{name:'string'},{sig:'string'},{modbits:'int'}])); } return res; } ); }, methods:function(ci) { // not supported by Dalvik - use methodsWithGeneric return new Command('Methods:'+ci.name, 2, 5, function() { var res=[]; DataCoder.encodeRef(res, ci.info.typeid); return res; }, function(o) { var arrlen = DataCoder.decodeInt(o); var res = []; while (--arrlen>=0) { res.push(DataCoder.decodeList(o, [{methodid:'mref'},{name:'string'},{sig:'string'},{modbits:'int'}])); } return res; } ); }, sourcefile:function(ci) { return new Command('SourceFile:'+ci.name, 2, 7, function() { var res=[]; DataCoder.encodeRef(res, ci.info.typeid); return res; }, function(o) { return [{'sourcefile':DataCoder.decodeString(o)}]; } ); }, fieldsWithGeneric:function(ci) { return new Command('FieldsWithGeneric:'+ci.name, 2, 14, function() { var res=[]; DataCoder.encodeRef(res, ci.info.typeid); return res; }, function(o) { var arrlen = DataCoder.decodeInt(o); var res = []; while (--arrlen>=0) { res.push(DataCoder.decodeList(o, [{fieldid:'fref'},{name:'string'},{type:'signature'},{genericsig:'string'},{modbits:'int'}])); } return res; } ); }, methodsWithGeneric:function(ci) { return new Command('MethodsWithGeneric:'+ci.name, 2, 15, function() { var res=[]; DataCoder.encodeRef(res, ci.info.typeid); return res; }, function(o) { var arrlen = DataCoder.decodeInt(o); var res = []; while (--arrlen>=0) { res.push(DataCoder.decodeList(o, [{methodid:'mref'},{name:'string'},{sig:'string'},{genericsig:'string'},{modbits:'int'}])); } return res; } ); }, superclass:function(ci) { return new Command('Superclass:'+ci.name, 3, 1, function() { var res=[]; DataCoder.encodeRef(res, ci.info.typeid); return res; }, function(o) { return DataCoder.decodeTRef(o); } ); }, signature:function(typeid) { return new Command('Signature:'+typeid, 2, 1, function() { var res=[]; DataCoder.encodeRef(res, typeid); return res; }, function(o) { return DataCoder.decodeTypeFromSignature(o); } ); }, nestedTypes:function(ci) { return new Command('NestedTypes:'+ci.name, 2, 8, function() { var res=[]; DataCoder.encodeRef(res, ci.info.typeid); return res; }, function(o) { var res=[]; var arrlen = DataCoder.decodeInt(o); while (--arrlen>=0) { var v = DataCoder.decodeList(o, [{reftype:'reftype'},{typeid:'tref'}]); res.vars.push(v); } return res; } ); }, lineTable:function(ci, mi) { return new Command('Linetable:'+ci.name+","+mi.name, 6, 1, function() { var res=[]; DataCoder.encodeRef(res, ci.info.typeid); DataCoder.encodeRef(res, mi.methodid); return res; }, function(o) { var res = {}; res.start = DataCoder.decodeLong(o, true); res.end = DataCoder.decodeLong(o, true); res.lines = []; var arrlen = DataCoder.decodeInt(o); while (--arrlen>=0) { var line = DataCoder.decodeList(o, [{linecodeidx:'codeindex'},{linenum:'int'}]); res.lines.push(line); } // sort the lines by...um..line number res.lines.sort(function(a,b) { return a.linenum-b.linenum || a.linecodeidx-b.linecodeidx; }) return res; } ); }, VariableTableWithGeneric:function(ci, mi) { // VariableTable is not supported by Dalvik return new Command('VariableTableWithGeneric:'+ci.name+","+mi.name, 6, 5, function() { var res=[]; DataCoder.encodeRef(res, ci.info.typeid); DataCoder.encodeRef(res, mi.methodid); return res; }, function(o) { var res = {}; res.argCnt = DataCoder.decodeInt(o); res.vars = []; var arrlen = DataCoder.decodeInt(o); while (--arrlen>=0) { var v = DataCoder.decodeList(o, [{codeidx:'codeindex'},{name:'string'},{type:'signature'},{genericsig:'string'},{length:'int'},{slot:'int'}]); res.vars.push(v); } return res; } ); }, Frames:function(threadid, start, count) { return new Command('Frames:'+threadid, 11, 6, function() { var res=[]; DataCoder.encodeRef(res, threadid); DataCoder.encodeInt(res, start||0); DataCoder.encodeInt(res, count||-1); return res; }, function(o) { var res = []; var arrlen = DataCoder.decodeInt(o); while (--arrlen>=0) { var v = DataCoder.decodeList(o, [{frameid:'frameid'},{location:'location'}]); res.push(v); } return res; } ); }, GetStackValues:function(threadid, frameid, slots) { return new Command('GetStackValues:'+threadid, 16, 1, function() { var res=[]; DataCoder.encodeRef(res, threadid); DataCoder.encodeRef(res, frameid); DataCoder.encodeInt(res, slots.length); for (var i in slots) { DataCoder.encodeInt(res, slots[i].slot); DataCoder.encodeByte(res, slots[i].tag); } return res; }, function(o) { var res = []; var arrlen = DataCoder.decodeInt(o); while (--arrlen>=0) { var v = DataCoder.decodeValue(o); res.push(v); } return res; } ); }, SetStackValue:function(threadid, frameid, slot, data) { return new Command('SetStackValue:'+threadid, 16, 2, function() { var res=[]; DataCoder.encodeRef(res, threadid); DataCoder.encodeRef(res, frameid); DataCoder.encodeInt(res, 1); DataCoder.encodeInt(res, slot); DataCoder.encodeTaggedValue(res, data.valuetype, data.value); return res; }, function(o) { // there's no return data - if we reach here, the update was successfull return true; } ); }, GetFieldValues:function(objectid, fields) { return new Command('GetFieldValues:'+objectid, 9, 2, function() { var res=[]; DataCoder.encodeRef(res, objectid); DataCoder.encodeInt(res, fields.length); for (var i in fields) { DataCoder.encodeRef(res, fields[i].fieldid); } return res; }, function(o) { var res = []; var arrlen = DataCoder.decodeInt(o); while (--arrlen>=0) { var v = DataCoder.decodeValue(o); res.push(v); } return res; } ); }, SetFieldValue:function(objectid, field, data) { return new Command('SetFieldValue:'+objectid, 9, 3, function() { var res=[]; DataCoder.encodeRef(res, objectid); DataCoder.encodeInt(res, 1); DataCoder.encodeRef(res, field.fieldid); DataCoder.encodeValue(res, data.valuetype, data.value); return res; }, function(o) { // there's no return data - if we reach here, the update was successfull return true; } ); }, GetArrayLength:function(arrobjid) { return new Command('GetArrayLength:'+arrobjid, 13, 1, function() { var res=[]; DataCoder.encodeRef(res, arrobjid); return res; }, function(o) { return DataCoder.decodeInt(o); } ); }, GetArrayValues:function(arrobjid, idx, count) { return new Command('GetArrayValues:'+arrobjid, 13, 2, function() { var res=[]; DataCoder.encodeRef(res, arrobjid); DataCoder.encodeInt(res, idx); DataCoder.encodeInt(res, count); return res; }, function(o) { var res = []; var tag = DataCoder.decodeByte(o); var decodefn = DataCoder.tagtodecoder(tag); // objects are decoded as values if (decodefn===DataCoder.decodeORef) decodefn = DataCoder.decodeValue; var arrlen = DataCoder.decodeInt(o); while (--arrlen>=0) { var v = decodefn.call(DataCoder, o); res.push(v); } return res; } ); }, SetArrayElements:function(arrobjid, idx, count, data) { return new Command('SetArrayElements:'+arrobjid, 13, 3, function() { var res=[]; DataCoder.encodeRef(res, arrobjid); DataCoder.encodeInt(res, idx); DataCoder.encodeInt(res, count); for (var i=0; i < count; i++) DataCoder.encodeValue(res, data.valuetype, data.value); return res; }, function(o) { // there's no return data - if we reach here, the update was successfull return true; } ); }, GetStringValue:function(strobjid) { return new Command('GetStringValue:'+strobjid, 10, 1, function() { var res=[]; DataCoder.encodeRef(res, strobjid); return res; }, function(o) { return DataCoder.decodeString(o); } ); }, CreateStringObject:function(text) { return new Command('CreateStringObject:'+text.substring(0,20), 1, 11, function() { var res=[]; DataCoder.encodeString(res, text); return res; }, function(o) { return DataCoder.decodeORef(o); } ); }, SetEventRequest:function(kindname, kind, suspend, modifiers, modifiercb, onevent) { return new Command('SetEventRequest:'+kindname, 15, 1, function() { var res=[kind,suspend]; DataCoder.encodeInt(res, modifiers.length); for (var i=0;i=0) { res.push(DataCoder.decodeList(o, [{reftype:'reftype'},{typeid:'tref'},{type:'signature'},{genericSignature:'string'},{status:'status'}])); } return res; } ); }, suspend:function() { return new Command('suspend',1, 8, null, null); }, resume:function() { return new Command('resume',1, 9, null, null); }, allthreads:function() { return new Command('allthreads',1, 4, null, function(o) { var res = []; var arrlen = DataCoder.decodeInt(o); while (--arrlen>=0) { res.push(DataCoder.decodeTRef(o)); } return res; } ); } }; } exports._JDWP = _JDWP;