001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.cldchi.tools.memoryprofiler.jdwp;
028:
029: import java.util.Vector;
030:
031: /**
032: * This class encapsulates JDWP packet. It based on
033: * <code>ByteBuffer</code> but adds methods for working with data
034: * specific for JDWP packet. This class is not used directly, its subclasses
035: * <code>Command</code> and <code>Reply</code> are used instead. For
036: * information about JDWP packet see JDWP specification.
037: *
038: * @see jdwp.ByteBuffer
039: * @see jdwp.Command
040: * @see jdwp.Reply
041: */
042: class Packet extends ByteBuffer {
043:
044: /**
045: * JDWP packet flag "no flags". Indicates that the packet is a command.
046: */
047: public final static int flNoFlags = 0x0;
048:
049: /**
050: * JDWP packet flag <code>Reply</code>. Indicates that the packet is a
051: * reply.
052: */
053: public final static int flReply = 0x80;
054:
055: /**
056: * Offset of the "packet length" field in the JDWP packet.
057: */
058: public final static int LengthOffset = 0;
059:
060: /**
061: * Offset of the "packet ID" field in the JDWP packet.
062: */
063: public final static int IdOffset = 4;
064:
065: /**
066: * Offset of the "flags" field in the JDWP packet.
067: */
068: public final static int FlagsOffset = 8;
069:
070: /**
071: * Offset of the "command number" field in the JDWP packet.
072: */
073: public final static int CommandOffset = 9;
074:
075: /**
076: * Offset of the "error code" field in the JDWP packet.
077: */
078: public final static int ErrorCodeOffset = 9;
079:
080: /**
081: * Size of JDWP packet's header.
082: */
083: public final static int PacketHeaderSize = 11;
084:
085: /**
086: * Create a new JDWP packet fills its header by zeros.
087: */
088: public Packet() {
089: super ();
090: while (length() < PacketHeaderSize) {
091: addByte(0);
092: }
093: }
094:
095: /**
096: * Sets "packet length" field of the JDWP packet
097: */
098: public void setLength() {
099: try {
100: putInt(LengthOffset, length());
101: } catch (BoundException e) {
102: }
103: ;
104: }
105:
106: /**
107: * Returns ID of the JDWP packet.
108: *
109: * @return ID of the JDWP packet
110: */
111: public int getID() {
112: int id = 0;
113:
114: try {
115: id = getInt(IdOffset);
116: } catch (BoundException e) {
117: }
118: ;
119: return id;
120: }
121:
122: /**
123: * Sets ID of the JDWP packet.
124: *
125: * @param Id ID of the JDWP packet
126: */
127: public void setID(int Id) {
128: try {
129: putInt(IdOffset, Id);
130: } catch (BoundException e) {
131: }
132: ;
133: }
134:
135: /**
136: * Returns flags of the JDWP packet.
137: *
138: * @return flags of the JDWP packet.
139: */
140: public int getFlags() {
141: return bytes[FlagsOffset] & 0xff;
142: }
143:
144: /**
145: * Sets flags of the JDWP packet.
146: *
147: * @param Flags flags to be set
148: */
149: public void setFlags(int Flags) {
150: bytes[FlagsOffset] = (byte) (Flags & 0xFF);
151: }
152:
153: /**
154: * Moves the reading marker to the beginning of packet data
155: * (after the header). To learn about reading marker see
156: * <code>ByteBuffer</code>.
157: *
158: * @see jdwp.ByteBuffer
159: */
160: public void resetDataParser() {
161: resetParser(PacketHeaderSize);
162: }
163:
164: /**
165: * Returns size of packet's data (i.e., size of the packet
166: * excluding header).
167: *
168: * @return size of packet's data
169: */
170: public int getDataSize() {
171: return length() - PacketHeaderSize;
172: }
173:
174: /**
175: * Adds a field ID to the end of JDWP packet.
176: *
177: * @param b ID to be added
178: */
179: public void addFieldID(long b) {
180: addID(b, jdwp.fieldIDSize);
181: }
182:
183: /**
184: * Adds a method ID to the end of JDWP packet.
185: *
186: * @param b ID to be added
187: */
188: public void addMethodID(long b) {
189: addID(b, jdwp.methodIDSize);
190: }
191:
192: /**
193: * Adds an object ID to the end of JDWP packet.
194: *
195: * @param b ID to be added
196: */
197: public void addObjectID(long b) {
198: addID(b, jdwp.objectIDSize);
199: }
200:
201: /**
202: * Adds a reference type ID to the end of JDWP packet.
203: *
204: * @param b ID to be added
205: */
206: public void addReferenceTypeID(long b) {
207: addID(b, jdwp.referenceTypeIDSize);
208: }
209:
210: /**
211: * Adds a frame ID to the end of JDWP packet.
212: *
213: * @param b ID to be added
214: */
215: public void addFrameID(long b) {
216: addID(b, jdwp.frameIDSize);
217: }
218:
219: /**
220: * Tries to read next field ID from the buffer.
221: * Value is read is one
222: * that is pointed by reading marker. After completing the operation
223: * the reading marker is incremented.
224: *
225: * @return current field ID from the buffer
226: * @throws BoundException if value to be read is outside the filled area
227: */
228: public long getFieldID() throws BoundException {
229: return getID(jdwp.fieldIDSize);
230: }
231:
232: /**
233: * Tries to read next method ID from the buffer.
234: * Value is read is one
235: * that is pointed by reading marker. After completing the operation
236: * the reading marker is incremented.
237: *
238: * @return current method ID from the buffer
239: * @throws BoundException if value to be read is outside the filled area
240: */
241: public long getMethodID() throws BoundException {
242: return getID(jdwp.methodIDSize);
243: }
244:
245: /**
246: * Tries to read next object ID from the buffer.
247: * Value is read is one
248: * that is pointed by reading marker. After completing the operation
249: * the reading marker is incremented.
250: *
251: * @return current object ID from the buffer
252: * @throws BoundException if value to be read is outside the filled area
253: */
254: public long getObjectID() throws BoundException {
255: return getID(jdwp.objectIDSize);
256: }
257:
258: /**
259: * Tries to read next reference type ID from the buffer.
260: * Value is read is one
261: * that is pointed by reading marker. After completing the operation
262: * the reading marker is incremented.
263: *
264: * @return current reference type ID from the buffer
265: * @throws BoundException if value to be read is outside the filled area
266: */
267: public long getReferenceTypeID() throws BoundException {
268: return getID(jdwp.referenceTypeIDSize);
269: }
270:
271: /**
272: * Tries to read next frame ID from the buffer.
273: * Value is read is one
274: * that is pointed by reading marker. After completing the operation
275: * the reading marker is incremented.
276: *
277: * @return current frame ID from the buffer
278: * @throws BoundException if value to be read is outside the filled area
279: */
280: public long getFrameID() throws BoundException {
281: return getID(jdwp.frameIDSize);
282: }
283:
284: /**
285: * Parses the JDWP packet according to the specified mask. The mask
286: * specifies what elements are contained in JDWP packet's data. The rules
287: * are as follows:
288: * <ul>
289: * <li> b - a byte value
290: * <li> i - an int value
291: * <li> S - a short value
292: * <li> l - a long value
293: * <li> s - a string value
294: * <li> f - a field ID
295: * <li> m - a method ID
296: * <li> o - an object ID
297: * <li> r - a reference type ID
298: * <li> F - a frame ID
299: * <li> v - a value. The first byte indicates type tag of the
300: * variable, the second is a variable's value.
301: * <li> . - a set of data in the end of packet that should not be parsed.
302: * <li> i(<submask>) - the first integer indicates how many times
303: * submask is appeared in the packet.
304: * </ul>
305: * For example, the mask <code>li(rm)</code> means that the first element
306: * of packet's data is a <code>long</code> value, then an <code>int</code>
307: * value that indicates how many times the pair "reference type ID -
308: * method ID" is appeared later.
309: *
310: * @param how a mask that indicates how to parse a packet.
311: * @return a vector of parsed elements of the packet's data. The classes
312: * that represent different types of elements are written below:
313: * <ul>
314: * <li> b - <code>java.lang.Integer</code>
315: * <li> i - <code>java.lang.Integer</code>
316: * <li> S - <code>java.lang.Integer</code>
317: * <li> l - <code>java.lang.Long</code>
318: * <li> s - <code>java.lang.String</code>
319: * <li> f - <code>java.lang.Long</code>
320: * <li> m - <code>java.lang.Long</code>
321: * <li> o - <code>java.lang.Long</code>
322: * <li> r - <code>java.lang.Long</code>
323: * <li> F - <code>java.lang.Long</code>
324: * <li> v - The tag of the value is represented by
325: * <code>java.lang.Integer</code>. The value itself is represented
326: * according to this table
327: * </ul>
328: */
329: public Vector parse(String how) throws BoundException {
330:
331: boolean check;
332: check = (how.indexOf('.') == -1);
333:
334: if (!check) {
335: if (how.indexOf('.') != how.length() - 1)
336: throw new BoundException();
337: how = Tools.Left(how, how.length() - 1);
338: }
339:
340: Vector v = new Vector();
341: resetDataParser();
342: doParse(how, v);
343:
344: if (check && (!isParsed()))
345: throw new BoundException();
346: return v;
347: }
348:
349: /**
350: * Performs the parsing of the JDWP oacket in fact. The all the
351: * parsing rules that described in the description of
352: * <code>parse</code> method are the same besides of absence of
353: * '.' symbol in the mask.
354: *
355: * @param how a mask that describes types of elements
356: * @param v a vector for keeping results
357: *
358: * @see #parse(java.lang.String)
359: */
360: private void doParse(String how, Vector v) throws BoundException {
361:
362: int index = 0;
363: char[] h = how.toCharArray();
364:
365: while (index < h.length) {
366: switch (h[index]) {
367: case 'b':
368: v.add(new Integer(getByte()));
369: break;
370: case 'i':
371: v.add(new Integer(getInt()));
372: break;
373: case 'S':
374: v.add(new Integer(getShort()));
375: break;
376: case 'l':
377: v.add(new Long(getLong()));
378: break;
379: case 's':
380: v.add(getString());
381: break;
382: case 'f':
383: v.add(new Long(getFieldID()));
384: break;
385: case 'm':
386: v.add(new Long(getMethodID()));
387: break;
388: case 'o':
389: v.add(new Long(getObjectID()));
390: break;
391: case 'r':
392: v.add(new Long(getReferenceTypeID()));
393: break;
394: case 'F':
395: v.add(new Long(getFrameID()));
396: break;
397: case 'v':
398: int vtype = getByte();
399: v.add(new Integer(vtype));
400: switch (vtype) {
401: case jdwp.tagARRAY:
402: case jdwp.tagOBJECT:
403: v.add(new Long(getObjectID()));
404: break;
405: case jdwp.tagBYTE:
406: v.add(new Integer(getByte()));
407: break;
408: case jdwp.tagINT:
409: v.add(new Integer(getInt()));
410: break;
411: case jdwp.tagSHORT:
412: v.add(new Integer(getShort()));
413: break;
414: case jdwp.tagVOID:
415: v.add("void value");
416: break;
417: case jdwp.tagBOOLEAN:
418: v.add(new Integer(getByte()));
419: break;
420: case jdwp.tagLONG:
421: v.add(new Long(getLong()));
422: break;
423: default:
424: throw new BoundException();
425: }
426: break;
427:
428: case '(':
429: if (index == 0)
430: throw new BoundException();
431:
432: if (h[index - 1] != 'i')
433: throw new BoundException();
434:
435: int n = ((Integer) v.elementAt(v.size() - 1))
436: .intValue();
437:
438: if (n < 0)
439: throw new BoundException();
440: int pos = index + 1;
441: int cnt = 1;
442: int last = -1;
443: while (pos < h.length) {
444: if (h[pos] == '(')
445: cnt++;
446:
447: if (h[pos] == ')') {
448: cnt--;
449: if (cnt == 0) {
450: last = pos;
451: break;
452: }
453: }
454: pos++;
455: }
456:
457: if (last == -1)
458: throw new BoundException();
459:
460: String s = new String(h, index + 1, last - index - 1);
461: for (int i = 0; i < n; i++)
462: doParse(s, v);
463: index = last;
464: break;
465:
466: default:
467: throw new BoundException();
468: }
469: index++;
470: }
471: }
472: }
|