blob: dd054c1ba0c275e53cf20218721da3f82ff319ee [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.tools.jdi;
27
28import com.sun.jdi.*;
29
30import java.util.*;
31import java.io.File;
32
33class SDE {
34 private static final int INIT_SIZE_FILE = 3;
35 private static final int INIT_SIZE_LINE = 100;
36 private static final int INIT_SIZE_STRATUM = 3;
37
38 static final String BASE_STRATUM_NAME = "Java";
39
40 /* for C capatibility */
41 static final String NullString = null;
42
43 private class FileTableRecord {
44 int fileId;
45 String sourceName;
46 String sourcePath; // do not read - use accessor
47 boolean isConverted = false;
48
49 /**
50 * Return the sourcePath, computing it if not set.
51 * If set, convert '/' in the sourcePath to the
52 * local file separator.
53 */
54 String getSourcePath(ReferenceTypeImpl refType) {
55 if (!isConverted) {
56 if (sourcePath == null) {
57 sourcePath = refType.baseSourceDir() + sourceName;
58 } else {
59 StringBuffer buf = new StringBuffer();
60 for (int i = 0; i < sourcePath.length(); ++i) {
61 char ch = sourcePath.charAt(i);
62 if (ch == '/') {
63 buf.append(File.separatorChar);
64 } else {
65 buf.append(ch);
66 }
67 }
68 sourcePath = buf.toString();
69 }
70 isConverted = true;
71 }
72 return sourcePath;
73 }
74 }
75
76 private class LineTableRecord {
77 int jplsStart;
78 int jplsEnd;
79 int jplsLineInc;
80 int njplsStart;
81 int njplsEnd;
82 int fileId;
83 }
84
85 private class StratumTableRecord {
86 String id;
87 int fileIndex;
88 int lineIndex;
89 }
90
91 class Stratum {
92 private final int sti; /* stratum index */
93
94 private Stratum(int sti) {
95 this.sti = sti;
96 }
97
98 String id() {
99 return stratumTable[sti].id;
100 }
101
102 boolean isJava() {
103 return sti == baseStratumIndex;
104 }
105
106 /**
107 * Return all the sourceNames for this stratum.
108 * Look from our starting fileIndex upto the starting
109 * fileIndex of next stratum - can do this since there
110 * is always a terminator stratum.
111 * Default sourceName (the first one) must be first.
112 */
113 List<String> sourceNames(ReferenceTypeImpl refType) {
114 int i;
115 int fileIndexStart = stratumTable[sti].fileIndex;
116 /* one past end */
117 int fileIndexEnd = stratumTable[sti+1].fileIndex;
118 List<String> result = new ArrayList<String>(fileIndexEnd - fileIndexStart);
119 for (i = fileIndexStart; i < fileIndexEnd; ++i) {
120 result.add(fileTable[i].sourceName);
121 }
122 return result;
123 }
124
125 /**
126 * Return all the sourcePaths for this stratum.
127 * Look from our starting fileIndex upto the starting
128 * fileIndex of next stratum - can do this since there
129 * is always a terminator stratum.
130 * Default sourcePath (the first one) must be first.
131 */
132 List<String> sourcePaths(ReferenceTypeImpl refType) {
133 int i;
134 int fileIndexStart = stratumTable[sti].fileIndex;
135 /* one past end */
136 int fileIndexEnd = stratumTable[sti+1].fileIndex;
137 List<String> result = new ArrayList<String>(fileIndexEnd - fileIndexStart);
138 for (i = fileIndexStart; i < fileIndexEnd; ++i) {
139 result.add(fileTable[i].getSourcePath(refType));
140 }
141 return result;
142 }
143
144 LineStratum lineStratum(ReferenceTypeImpl refType,
145 int jplsLine) {
146 int lti = stiLineTableIndex(sti, jplsLine);
147 if (lti < 0) {
148 return null;
149 } else {
150 return new LineStratum(sti, lti, refType,
151 jplsLine);
152 }
153 }
154 }
155
156 class LineStratum {
157 private final int sti; /* stratum index */
158 private final int lti; /* line table index */
159 private final ReferenceTypeImpl refType;
160 private final int jplsLine;
161 private String sourceName = null;
162 private String sourcePath = null;
163
164 private LineStratum(int sti, int lti,
165 ReferenceTypeImpl refType,
166 int jplsLine) {
167 this.sti = sti;
168 this.lti = lti;
169 this.refType = refType;
170 this.jplsLine = jplsLine;
171 }
172
173 public boolean equals(Object obj) {
174 if ((obj != null) && (obj instanceof LineStratum)) {
175 LineStratum other = (LineStratum)obj;
176 return (lti == other.lti) &&
177 (sti == other.sti) &&
178 (lineNumber() == other.lineNumber()) &&
179 (refType.equals(other.refType));
180 } else {
181 return false;
182 }
183 }
184
185 int lineNumber() {
186 return stiLineNumber(sti, lti, jplsLine);
187 }
188
189 /**
190 * Fetch the source name and source path for
191 * this line, converting or constructing
192 * the source path if needed.
193 */
194 void getSourceInfo() {
195 if (sourceName != null) {
196 // already done
197 return;
198 }
199 int fti = stiFileTableIndex(sti, lti);
200 if (fti == -1) {
201 throw new InternalError(
202 "Bad SourceDebugExtension, no matching source id " +
203 lineTable[lti].fileId + " jplsLine: " + jplsLine);
204 }
205 FileTableRecord ftr = fileTable[fti];
206 sourceName = ftr.sourceName;
207 sourcePath = ftr.getSourcePath(refType);
208 }
209
210 String sourceName() {
211 getSourceInfo();
212 return sourceName;
213 }
214
215 String sourcePath() {
216 getSourceInfo();
217 return sourcePath;
218 }
219 }
220
221 private FileTableRecord[] fileTable = null;
222 private LineTableRecord[] lineTable = null;
223 private StratumTableRecord[] stratumTable = null;
224
225 private int fileIndex = 0;
226 private int lineIndex = 0;
227 private int stratumIndex = 0;
228 private int currentFileId = 0;
229
230 private int defaultStratumIndex = -1;
231 private int baseStratumIndex = -2; /* so as not to match -1 above */
232 private int sdePos = 0;
233
234 final String sourceDebugExtension;
235 String jplsFilename = null;
236 String defaultStratumId = null;
237 boolean isValid = false;
238
239 SDE(String sourceDebugExtension) {
240 this.sourceDebugExtension = sourceDebugExtension;
241 decode();
242 }
243
244 SDE() {
245 this.sourceDebugExtension = null;
246 createProxyForAbsentSDE();
247 }
248
249 char sdePeek() {
250 if (sdePos >= sourceDebugExtension.length()) {
251 syntax();
252 }
253 return sourceDebugExtension.charAt(sdePos);
254 }
255
256 char sdeRead() {
257 if (sdePos >= sourceDebugExtension.length()) {
258 syntax();
259 }
260 return sourceDebugExtension.charAt(sdePos++);
261 }
262
263 void sdeAdvance() {
264 sdePos++;
265 }
266
267 void syntax() {
268 throw new InternalError("bad SourceDebugExtension syntax - position " +
269 sdePos);
270 }
271
272 void syntax(String msg) {
273 throw new InternalError("bad SourceDebugExtension syntax: " + msg);
274 }
275
276 void assureLineTableSize() {
277 int len = lineTable == null? 0 : lineTable.length;
278 if (lineIndex >= len) {
279 int i;
280 int newLen = len == 0? INIT_SIZE_LINE : len * 2;
281 LineTableRecord[] newTable = new LineTableRecord[newLen];
282 for (i = 0; i < len; ++i) {
283 newTable[i] = lineTable[i];
284 }
285 for (; i < newLen; ++i) {
286 newTable[i] = new LineTableRecord();
287 }
288 lineTable = newTable;
289 }
290 }
291
292 void assureFileTableSize() {
293 int len = fileTable == null? 0 : fileTable.length;
294 if (fileIndex >= len) {
295 int i;
296 int newLen = len == 0? INIT_SIZE_FILE : len * 2;
297 FileTableRecord[] newTable = new FileTableRecord[newLen];
298 for (i = 0; i < len; ++i) {
299 newTable[i] = fileTable[i];
300 }
301 for (; i < newLen; ++i) {
302 newTable[i] = new FileTableRecord();
303 }
304 fileTable = newTable;
305 }
306 }
307
308 void assureStratumTableSize() {
309 int len = stratumTable == null? 0 : stratumTable.length;
310 if (stratumIndex >= len) {
311 int i;
312 int newLen = len == 0? INIT_SIZE_STRATUM : len * 2;
313 StratumTableRecord[] newTable = new StratumTableRecord[newLen];
314 for (i = 0; i < len; ++i) {
315 newTable[i] = stratumTable[i];
316 }
317 for (; i < newLen; ++i) {
318 newTable[i] = new StratumTableRecord();
319 }
320 stratumTable = newTable;
321 }
322 }
323
324 String readLine() {
325 StringBuffer sb = new StringBuffer();
326 char ch;
327
328 ignoreWhite();
329 while (((ch = sdeRead()) != '\n') && (ch != '\r')) {
330 sb.append((char)ch);
331 }
332 // check for CR LF
333 if ((ch == '\r') && (sdePeek() == '\n')) {
334 sdeRead();
335 }
336 ignoreWhite(); // leading white
337 return sb.toString();
338 }
339
340 private int defaultStratumTableIndex() {
341 if ((defaultStratumIndex == -1) && (defaultStratumId != null)) {
342 defaultStratumIndex =
343 stratumTableIndex(defaultStratumId);
344 }
345 return defaultStratumIndex;
346 }
347
348 int stratumTableIndex(String stratumId) {
349 int i;
350
351 if (stratumId == null) {
352 return defaultStratumTableIndex();
353 }
354 for (i = 0; i < (stratumIndex-1); ++i) {
355 if (stratumTable[i].id.equals(stratumId)) {
356 return i;
357 }
358 }
359 return defaultStratumTableIndex();
360 }
361
362 Stratum stratum(String stratumID) {
363 int sti = stratumTableIndex(stratumID);
364 return new Stratum(sti);
365 }
366
367 List<String> availableStrata() {
368 List<String> strata = new ArrayList<String>();
369
370 for (int i = 0; i < (stratumIndex-1); ++i) {
371 StratumTableRecord rec = stratumTable[i];
372 strata.add(rec.id);
373 }
374 return strata;
375 }
376
377/*****************************
378 * below functions/methods are written to compile under either Java or C
379 *
380 * Needed support functions:
381 * sdePeek()
382 * sdeRead()
383 * sdeAdvance()
384 * readLine()
385 * assureLineTableSize()
386 * assureFileTableSize()
387 * assureStratumTableSize()
388 * syntax()
389 *
390 * stratumTableIndex(String)
391 *
392 * Needed support variables:
393 * lineTable
394 * lineIndex
395 * fileTable
396 * fileIndex
397 * currentFileId
398 *
399 * Needed types:
400 * String
401 *
402 * Needed constants:
403 * NullString
404 */
405
406 void ignoreWhite() {
407 char ch;
408
409 while (((ch = sdePeek()) == ' ') || (ch == '\t')) {
410 sdeAdvance();
411 }
412 }
413
414 void ignoreLine() {
415 char ch;
416
417 while (((ch = sdeRead()) != '\n') && (ch != '\r')) {
418 }
419 /* check for CR LF */
420 if ((ch == '\r') && (sdePeek() == '\n')) {
421 sdeAdvance();
422 }
423 ignoreWhite(); /* leading white */
424 }
425
426 int readNumber() {
427 int value = 0;
428 char ch;
429
430 ignoreWhite();
431 while (((ch = sdePeek()) >= '0') && (ch <= '9')) {
432 sdeAdvance();
433 value = (value * 10) + ch - '0';
434 }
435 ignoreWhite();
436 return value;
437 }
438
439 void storeFile(int fileId, String sourceName, String sourcePath) {
440 assureFileTableSize();
441 fileTable[fileIndex].fileId = fileId;
442 fileTable[fileIndex].sourceName = sourceName;
443 fileTable[fileIndex].sourcePath = sourcePath;
444 ++fileIndex;
445 }
446
447 void fileLine() {
448 int hasAbsolute = 0; /* acts as boolean */
449 int fileId;
450 String sourceName;
451 String sourcePath = null;
452
453 /* is there an absolute filename? */
454 if (sdePeek() == '+') {
455 sdeAdvance();
456 hasAbsolute = 1;
457 }
458 fileId = readNumber();
459 sourceName = readLine();
460 if (hasAbsolute == 1) {
461 sourcePath = readLine();
462 }
463
464 storeFile(fileId, sourceName, sourcePath);
465 }
466
467 void storeLine(int jplsStart, int jplsEnd, int jplsLineInc,
468 int njplsStart, int njplsEnd, int fileId) {
469 assureLineTableSize();
470 lineTable[lineIndex].jplsStart = jplsStart;
471 lineTable[lineIndex].jplsEnd = jplsEnd;
472 lineTable[lineIndex].jplsLineInc = jplsLineInc;
473 lineTable[lineIndex].njplsStart = njplsStart;
474 lineTable[lineIndex].njplsEnd = njplsEnd;
475 lineTable[lineIndex].fileId = fileId;
476 ++lineIndex;
477 }
478
479 /**
480 * Parse line translation info. Syntax is
481 * <NJ-start-line> [ # <file-id> ] [ , <line-count> ] :
482 * <J-start-line> [ , <line-increment> ] CR
483 */
484 void lineLine() {
485 int lineCount = 1;
486 int lineIncrement = 1;
487 int njplsStart;
488 int jplsStart;
489
490 njplsStart = readNumber();
491
492 /* is there a fileID? */
493 if (sdePeek() == '#') {
494 sdeAdvance();
495 currentFileId = readNumber();
496 }
497
498 /* is there a line count? */
499 if (sdePeek() == ',') {
500 sdeAdvance();
501 lineCount = readNumber();
502 }
503
504 if (sdeRead() != ':') {
505 syntax();
506 }
507 jplsStart = readNumber();
508 if (sdePeek() == ',') {
509 sdeAdvance();
510 lineIncrement = readNumber();
511 }
512 ignoreLine(); /* flush the rest */
513
514 storeLine(jplsStart,
515 jplsStart + (lineCount * lineIncrement) -1,
516 lineIncrement,
517 njplsStart,
518 njplsStart + lineCount -1,
519 currentFileId);
520 }
521
522 /**
523 * Until the next stratum section, everything after this
524 * is in stratumId - so, store the current indicies.
525 */
526 void storeStratum(String stratumId) {
527 /* remove redundant strata */
528 if (stratumIndex > 0) {
529 if ((stratumTable[stratumIndex-1].fileIndex
530 == fileIndex) &&
531 (stratumTable[stratumIndex-1].lineIndex
532 == lineIndex)) {
533 /* nothing changed overwrite it */
534 --stratumIndex;
535 }
536 }
537 /* store the results */
538 assureStratumTableSize();
539 stratumTable[stratumIndex].id = stratumId;
540 stratumTable[stratumIndex].fileIndex = fileIndex;
541 stratumTable[stratumIndex].lineIndex = lineIndex;
542 ++stratumIndex;
543 currentFileId = 0;
544 }
545
546 /**
547 * The beginning of a stratum's info
548 */
549 void stratumSection() {
550 storeStratum(readLine());
551 }
552
553 void fileSection() {
554 ignoreLine();
555 while (sdePeek() != '*') {
556 fileLine();
557 }
558 }
559
560 void lineSection() {
561 ignoreLine();
562 while (sdePeek() != '*') {
563 lineLine();
564 }
565 }
566
567 /**
568 * Ignore a section we don't know about.
569 */
570 void ignoreSection() {
571 ignoreLine();
572 while (sdePeek() != '*') {
573 ignoreLine();
574 }
575 }
576
577 /**
578 * A base "Java" stratum is always available, though
579 * it is not in the SourceDebugExtension.
580 * Create the base stratum.
581 */
582 void createJavaStratum() {
583 baseStratumIndex = stratumIndex;
584 storeStratum(BASE_STRATUM_NAME);
585 storeFile(1, jplsFilename, NullString);
586 /* JPL line numbers cannot exceed 65535 */
587 storeLine(1, 65536, 1, 1, 65536, 1);
588 storeStratum("Aux"); /* in case they don't declare */
589 }
590
591 /**
592 * Decode a SourceDebugExtension which is in SourceMap format.
593 * This is the entry point into the recursive descent parser.
594 */
595 void decode() {
596 /* check for "SMAP" - allow EOF if not ours */
597 if ((sourceDebugExtension.length() < 4) ||
598 (sdeRead() != 'S') ||
599 (sdeRead() != 'M') ||
600 (sdeRead() != 'A') ||
601 (sdeRead() != 'P')) {
602 return; /* not our info */
603 }
604 ignoreLine(); /* flush the rest */
605 jplsFilename = readLine();
606 defaultStratumId = readLine();
607 createJavaStratum();
608 while (true) {
609 if (sdeRead() != '*') {
610 syntax();
611 }
612 switch (sdeRead()) {
613 case 'S':
614 stratumSection();
615 break;
616 case 'F':
617 fileSection();
618 break;
619 case 'L':
620 lineSection();
621 break;
622 case 'E':
623 /* set end points */
624 storeStratum("*terminator*");
625 isValid = true;
626 return;
627 default:
628 ignoreSection();
629 }
630 }
631 }
632
633 void createProxyForAbsentSDE() {
634 jplsFilename = null;
635 defaultStratumId = BASE_STRATUM_NAME;
636 defaultStratumIndex = stratumIndex;
637 createJavaStratum();
638 storeStratum("*terminator*");
639 }
640
641 /***************** query functions ***********************/
642
643 private int stiLineTableIndex(int sti, int jplsLine) {
644 int i;
645 int lineIndexStart;
646 int lineIndexEnd;
647
648 lineIndexStart = stratumTable[sti].lineIndex;
649 /* one past end */
650 lineIndexEnd = stratumTable[sti+1].lineIndex;
651 for (i = lineIndexStart; i < lineIndexEnd; ++i) {
652 if ((jplsLine >= lineTable[i].jplsStart) &&
653 (jplsLine <= lineTable[i].jplsEnd)) {
654 return i;
655 }
656 }
657 return -1;
658 }
659
660 private int stiLineNumber(int sti, int lti, int jplsLine) {
661 return lineTable[lti].njplsStart +
662 (((jplsLine - lineTable[lti].jplsStart) /
663 lineTable[lti].jplsLineInc));
664 }
665
666 private int fileTableIndex(int sti, int fileId) {
667 int i;
668 int fileIndexStart = stratumTable[sti].fileIndex;
669 /* one past end */
670 int fileIndexEnd = stratumTable[sti+1].fileIndex;
671 for (i = fileIndexStart; i < fileIndexEnd; ++i) {
672 if (fileTable[i].fileId == fileId) {
673 return i;
674 }
675 }
676 return -1;
677 }
678
679 private int stiFileTableIndex(int sti, int lti) {
680 return fileTableIndex(sti, lineTable[lti].fileId);
681 }
682
683 boolean isValid() {
684 return isValid;
685 }
686}