• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2001, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.tools.jdi;
27 
28 import com.sun.jdi.*;
29 
30 import java.util.*;
31 import java.io.File;
32 
33 class 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          */
getSourcePath(ReferenceTypeImpl refType)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 
Stratum(int sti)94         private Stratum(int sti) {
95             this.sti = sti;
96         }
97 
id()98         String id() {
99             return stratumTable[sti].id;
100         }
101 
isJava()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          */
sourceNames(ReferenceTypeImpl refType)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          */
sourcePaths(ReferenceTypeImpl refType)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 
lineStratum(ReferenceTypeImpl refType, int jplsLine)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 
LineStratum(int sti, int lti, ReferenceTypeImpl refType, int jplsLine)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 
equals(Object obj)173         public boolean equals(Object obj) {
174             if (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         @Override
hashCode()186         public int hashCode() {
187             return (lineNumber() * 17) ^ refType.hashCode();
188         }
189 
lineNumber()190         int lineNumber() {
191             return stiLineNumber(sti, lti, jplsLine);
192         }
193 
194         /**
195          * Fetch the source name and source path for
196          * this line, converting or constructing
197          * the source path if needed.
198          */
getSourceInfo()199         void getSourceInfo() {
200             if (sourceName != null) {
201                 // already done
202                 return;
203             }
204             int fti = stiFileTableIndex(sti, lti);
205             if (fti == -1) {
206                 throw new InternalError(
207               "Bad SourceDebugExtension, no matching source id " +
208               lineTable[lti].fileId + " jplsLine: " + jplsLine);
209             }
210             FileTableRecord ftr = fileTable[fti];
211             sourceName = ftr.sourceName;
212             sourcePath = ftr.getSourcePath(refType);
213         }
214 
sourceName()215         String sourceName() {
216             getSourceInfo();
217             return sourceName;
218         }
219 
sourcePath()220         String sourcePath() {
221             getSourceInfo();
222             return sourcePath;
223         }
224     }
225 
226     private FileTableRecord[] fileTable = null;
227     private LineTableRecord[] lineTable = null;
228     private StratumTableRecord[] stratumTable = null;
229 
230     private int fileIndex = 0;
231     private int lineIndex = 0;
232     private int stratumIndex = 0;
233     private int currentFileId = 0;
234 
235     private int defaultStratumIndex = -1;
236     private int baseStratumIndex = -2; /* so as not to match -1 above */
237     private int sdePos = 0;
238 
239     final String sourceDebugExtension;
240     String jplsFilename = null;
241     String defaultStratumId = null;
242     boolean isValid = false;
243 
SDE(String sourceDebugExtension)244     SDE(String sourceDebugExtension) {
245         this.sourceDebugExtension = sourceDebugExtension;
246         decode();
247     }
248 
SDE()249     SDE() {
250         this.sourceDebugExtension = null;
251         createProxyForAbsentSDE();
252     }
253 
sdePeek()254     char sdePeek() {
255         if (sdePos >= sourceDebugExtension.length()) {
256             syntax();
257         }
258         return sourceDebugExtension.charAt(sdePos);
259     }
260 
sdeRead()261     char sdeRead() {
262         if (sdePos >= sourceDebugExtension.length()) {
263             syntax();
264         }
265         return sourceDebugExtension.charAt(sdePos++);
266     }
267 
sdeAdvance()268     void sdeAdvance() {
269         sdePos++;
270     }
271 
syntax()272     void syntax() {
273         throw new InternalError("bad SourceDebugExtension syntax - position " +
274                                 sdePos);
275     }
276 
syntax(String msg)277     void syntax(String msg) {
278         throw new InternalError("bad SourceDebugExtension syntax: " + msg);
279     }
280 
assureLineTableSize()281     void assureLineTableSize() {
282         int len = lineTable == null? 0 : lineTable.length;
283         if (lineIndex >= len) {
284             int i;
285             int newLen = len == 0? INIT_SIZE_LINE : len * 2;
286             LineTableRecord[] newTable = new LineTableRecord[newLen];
287             for (i = 0; i < len; ++i) {
288                 newTable[i] = lineTable[i];
289             }
290             for (; i < newLen; ++i) {
291                 newTable[i] = new LineTableRecord();
292             }
293             lineTable = newTable;
294         }
295     }
296 
assureFileTableSize()297     void assureFileTableSize() {
298         int len = fileTable == null? 0 : fileTable.length;
299         if (fileIndex >= len) {
300             int i;
301             int newLen = len == 0? INIT_SIZE_FILE : len * 2;
302             FileTableRecord[] newTable = new FileTableRecord[newLen];
303             for (i = 0; i < len; ++i) {
304                 newTable[i] = fileTable[i];
305             }
306             for (; i < newLen; ++i) {
307                 newTable[i] = new FileTableRecord();
308             }
309             fileTable = newTable;
310         }
311     }
312 
assureStratumTableSize()313     void assureStratumTableSize() {
314         int len = stratumTable == null? 0 : stratumTable.length;
315         if (stratumIndex >= len) {
316             int i;
317             int newLen = len == 0? INIT_SIZE_STRATUM : len * 2;
318             StratumTableRecord[] newTable = new StratumTableRecord[newLen];
319             for (i = 0; i < len; ++i) {
320                 newTable[i] = stratumTable[i];
321             }
322             for (; i < newLen; ++i) {
323                 newTable[i] = new StratumTableRecord();
324             }
325             stratumTable = newTable;
326         }
327     }
328 
readLine()329     String readLine() {
330         StringBuffer sb = new StringBuffer();
331         char ch;
332 
333         ignoreWhite();
334         while (((ch = sdeRead()) != '\n') && (ch != '\r')) {
335             sb.append(ch);
336         }
337         // check for CR LF
338         if ((ch == '\r') && (sdePeek() == '\n')) {
339             sdeRead();
340         }
341         ignoreWhite(); // leading white
342         return sb.toString();
343     }
344 
defaultStratumTableIndex()345     private int defaultStratumTableIndex() {
346         if ((defaultStratumIndex == -1) && (defaultStratumId != null)) {
347             defaultStratumIndex =
348                 stratumTableIndex(defaultStratumId);
349         }
350         return defaultStratumIndex;
351     }
352 
stratumTableIndex(String stratumId)353     int stratumTableIndex(String stratumId) {
354         int i;
355 
356         if (stratumId == null) {
357             return defaultStratumTableIndex();
358         }
359         for (i = 0; i < (stratumIndex-1); ++i) {
360             if (stratumTable[i].id.equals(stratumId)) {
361                 return i;
362             }
363         }
364         return defaultStratumTableIndex();
365     }
366 
stratum(String stratumID)367     Stratum stratum(String stratumID) {
368         int sti = stratumTableIndex(stratumID);
369         return new Stratum(sti);
370     }
371 
availableStrata()372     List<String> availableStrata() {
373         List<String> strata = new ArrayList<String>();
374 
375         for (int i = 0; i < (stratumIndex-1); ++i) {
376             StratumTableRecord rec = stratumTable[i];
377             strata.add(rec.id);
378         }
379         return strata;
380     }
381 
382 /*****************************
383  * below functions/methods are written to compile under either Java or C
384  *
385  * Needed support functions:
386  *   sdePeek()
387  *   sdeRead()
388  *   sdeAdvance()
389  *   readLine()
390  *   assureLineTableSize()
391  *   assureFileTableSize()
392  *   assureStratumTableSize()
393  *   syntax()
394  *
395  *   stratumTableIndex(String)
396  *
397  * Needed support variables:
398  *   lineTable
399  *   lineIndex
400  *   fileTable
401  *   fileIndex
402  *   currentFileId
403  *
404  * Needed types:
405  *   String
406  *
407  * Needed constants:
408  *   NullString
409  */
410 
ignoreWhite()411     void ignoreWhite() {
412         char ch;
413 
414         while (((ch = sdePeek()) == ' ') || (ch == '\t')) {
415             sdeAdvance();
416         }
417     }
418 
ignoreLine()419     void ignoreLine() {
420         char ch;
421 
422         while (((ch = sdeRead()) != '\n') && (ch != '\r')) {
423         }
424         /* check for CR LF */
425         if ((ch == '\r') && (sdePeek() == '\n')) {
426             sdeAdvance();
427         }
428         ignoreWhite(); /* leading white */
429     }
430 
readNumber()431     int readNumber() {
432         int value = 0;
433         char ch;
434 
435         ignoreWhite();
436         while (((ch = sdePeek()) >= '0') && (ch <= '9')) {
437             sdeAdvance();
438             value = (value * 10) + ch - '0';
439         }
440         ignoreWhite();
441         return value;
442     }
443 
storeFile(int fileId, String sourceName, String sourcePath)444     void storeFile(int fileId, String sourceName, String sourcePath) {
445         assureFileTableSize();
446         fileTable[fileIndex].fileId = fileId;
447         fileTable[fileIndex].sourceName = sourceName;
448         fileTable[fileIndex].sourcePath = sourcePath;
449         ++fileIndex;
450     }
451 
fileLine()452     void fileLine() {
453         int hasAbsolute = 0; /* acts as boolean */
454         int fileId;
455         String sourceName;
456         String sourcePath = null;
457 
458         /* is there an absolute filename? */
459         if (sdePeek() == '+') {
460             sdeAdvance();
461             hasAbsolute = 1;
462         }
463         fileId = readNumber();
464         sourceName = readLine();
465         if (hasAbsolute == 1) {
466             sourcePath = readLine();
467         }
468 
469         storeFile(fileId, sourceName, sourcePath);
470     }
471 
storeLine(int jplsStart, int jplsEnd, int jplsLineInc, int njplsStart, int njplsEnd, int fileId)472     void storeLine(int jplsStart, int jplsEnd, int jplsLineInc,
473                   int njplsStart, int njplsEnd, int fileId) {
474         assureLineTableSize();
475         lineTable[lineIndex].jplsStart = jplsStart;
476         lineTable[lineIndex].jplsEnd = jplsEnd;
477         lineTable[lineIndex].jplsLineInc = jplsLineInc;
478         lineTable[lineIndex].njplsStart = njplsStart;
479         lineTable[lineIndex].njplsEnd = njplsEnd;
480         lineTable[lineIndex].fileId = fileId;
481         ++lineIndex;
482     }
483 
484     /**
485      * Parse line translation info.  Syntax is
486      *     <NJ-start-line> [ # <file-id> ] [ , <line-count> ] :
487      *                 <J-start-line> [ , <line-increment> ] CR
488      */
lineLine()489     void lineLine() {
490         int lineCount = 1;
491         int lineIncrement = 1;
492         int njplsStart;
493         int jplsStart;
494 
495         njplsStart = readNumber();
496 
497         /* is there a fileID? */
498         if (sdePeek() == '#') {
499             sdeAdvance();
500             currentFileId = readNumber();
501         }
502 
503         /* is there a line count? */
504         if (sdePeek() == ',') {
505             sdeAdvance();
506             lineCount = readNumber();
507         }
508 
509         if (sdeRead() != ':') {
510             syntax();
511         }
512         jplsStart = readNumber();
513         if (sdePeek() == ',') {
514             sdeAdvance();
515             lineIncrement = readNumber();
516         }
517         ignoreLine(); /* flush the rest */
518 
519         storeLine(jplsStart,
520                   jplsStart + (lineCount * lineIncrement) -1,
521                   lineIncrement,
522                   njplsStart,
523                   njplsStart + lineCount -1,
524                   currentFileId);
525     }
526 
527     /**
528      * Until the next stratum section, everything after this
529      * is in stratumId - so, store the current indicies.
530      */
storeStratum(String stratumId)531     void storeStratum(String stratumId) {
532         /* remove redundant strata */
533         if (stratumIndex > 0) {
534             if ((stratumTable[stratumIndex-1].fileIndex
535                                             == fileIndex) &&
536                 (stratumTable[stratumIndex-1].lineIndex
537                                             == lineIndex)) {
538                 /* nothing changed overwrite it */
539                 --stratumIndex;
540             }
541         }
542         /* store the results */
543         assureStratumTableSize();
544         stratumTable[stratumIndex].id = stratumId;
545         stratumTable[stratumIndex].fileIndex = fileIndex;
546         stratumTable[stratumIndex].lineIndex = lineIndex;
547         ++stratumIndex;
548         currentFileId = 0;
549     }
550 
551     /**
552      * The beginning of a stratum's info
553      */
stratumSection()554     void stratumSection() {
555         storeStratum(readLine());
556     }
557 
fileSection()558     void fileSection() {
559         ignoreLine();
560         while (sdePeek() != '*') {
561             fileLine();
562         }
563     }
564 
lineSection()565     void lineSection() {
566         ignoreLine();
567         while (sdePeek() != '*') {
568             lineLine();
569         }
570     }
571 
572     /**
573      * Ignore a section we don't know about.
574      */
ignoreSection()575     void ignoreSection() {
576         ignoreLine();
577         while (sdePeek() != '*') {
578             ignoreLine();
579         }
580     }
581 
582     /**
583      * A base "Java" stratum is always available, though
584      * it is not in the SourceDebugExtension.
585      * Create the base stratum.
586      */
createJavaStratum()587     void createJavaStratum() {
588         baseStratumIndex = stratumIndex;
589         storeStratum(BASE_STRATUM_NAME);
590         storeFile(1, jplsFilename, NullString);
591         /* JPL line numbers cannot exceed 65535 */
592         storeLine(1, 65536, 1, 1, 65536, 1);
593         storeStratum("Aux"); /* in case they don't declare */
594     }
595 
596     /**
597      * Decode a SourceDebugExtension which is in SourceMap format.
598      * This is the entry point into the recursive descent parser.
599      */
decode()600     void decode() {
601         /* check for "SMAP" - allow EOF if not ours */
602         if ((sourceDebugExtension.length() < 4) ||
603             (sdeRead() != 'S') ||
604             (sdeRead() != 'M') ||
605             (sdeRead() != 'A') ||
606             (sdeRead() != 'P')) {
607             return; /* not our info */
608         }
609         ignoreLine(); /* flush the rest */
610         jplsFilename = readLine();
611         defaultStratumId = readLine();
612         createJavaStratum();
613         while (true) {
614             if (sdeRead() != '*') {
615                 syntax();
616             }
617             switch (sdeRead()) {
618                 case 'S':
619                     stratumSection();
620                     break;
621                 case 'F':
622                     fileSection();
623                     break;
624                 case 'L':
625                     lineSection();
626                     break;
627                 case 'E':
628                     /* set end points */
629                     storeStratum("*terminator*");
630                     isValid = true;
631                     return;
632                 default:
633                     ignoreSection();
634             }
635         }
636     }
637 
createProxyForAbsentSDE()638     void createProxyForAbsentSDE() {
639         jplsFilename = null;
640         defaultStratumId = BASE_STRATUM_NAME;
641         defaultStratumIndex = stratumIndex;
642         createJavaStratum();
643         storeStratum("*terminator*");
644     }
645 
646     /***************** query functions ***********************/
647 
stiLineTableIndex(int sti, int jplsLine)648     private int stiLineTableIndex(int sti, int jplsLine) {
649         int i;
650         int lineIndexStart;
651         int lineIndexEnd;
652 
653         lineIndexStart = stratumTable[sti].lineIndex;
654         /* one past end */
655         lineIndexEnd = stratumTable[sti+1].lineIndex;
656         for (i = lineIndexStart; i < lineIndexEnd; ++i) {
657             if ((jplsLine >= lineTable[i].jplsStart) &&
658                             (jplsLine <= lineTable[i].jplsEnd)) {
659                 return i;
660             }
661         }
662         return -1;
663     }
664 
stiLineNumber(int sti, int lti, int jplsLine)665     private int stiLineNumber(int sti, int lti, int jplsLine) {
666         return lineTable[lti].njplsStart +
667                 (((jplsLine - lineTable[lti].jplsStart) /
668                                    lineTable[lti].jplsLineInc));
669     }
670 
fileTableIndex(int sti, int fileId)671     private int fileTableIndex(int sti, int fileId) {
672         int i;
673         int fileIndexStart = stratumTable[sti].fileIndex;
674         /* one past end */
675         int fileIndexEnd = stratumTable[sti+1].fileIndex;
676         for (i = fileIndexStart; i < fileIndexEnd; ++i) {
677             if (fileTable[i].fileId == fileId) {
678                 return i;
679             }
680         }
681         return -1;
682     }
683 
stiFileTableIndex(int sti, int lti)684     private int stiFileTableIndex(int sti, int lti) {
685         return fileTableIndex(sti, lineTable[lti].fileId);
686     }
687 
isValid()688     boolean isValid() {
689         return isValid;
690     }
691 }
692