blob: 87900be21bfd42058419c2dada65ccef2e2cd6f5 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2005 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
26#include <setjmp.h>
27
28#include "util.h"
29#include "SDE.h"
30
31/**
32 * This SourceDebugExtension code does not
33 * allow concurrent translation - due to caching method.
34 * A separate thread setting the default stratum ID
35 * is, however, fine.
36 */
37
38#define INIT_SIZE_FILE 10
39#define INIT_SIZE_LINE 100
40#define INIT_SIZE_STRATUM 3
41
42#define BASE_STRATUM_NAME "Java"
43
44#define null NULL
45#define true JNI_TRUE
46#define false JNI_FALSE
47#define String char *
48#define private static
49
50typedef struct {
51 int fileId;
52 String sourceName;
53 String sourcePath; // do not read - use accessor
54 int isConverted;
55} FileTableRecord;
56
57typedef struct {
58 int jplsStart;
59 int jplsEnd;
60 int jplsLineInc;
61 int njplsStart;
62 int njplsEnd;
63 int fileId;
64} LineTableRecord;
65
66typedef struct {
67 String id;
68 int fileIndex;
69 int lineIndex;
70} StratumTableRecord;
71
72/* back-end wide value for default stratum */
73private String globalDefaultStratumId = null;
74
75/* reference type default */
76private String defaultStratumId = null;
77
78private jclass cachedClass = NULL;
79
80private FileTableRecord* fileTable;
81private LineTableRecord* lineTable;
82private StratumTableRecord* stratumTable;
83
84private int fileTableSize;
85private int lineTableSize;
86private int stratumTableSize;
87
88private int fileIndex;
89private int lineIndex;
90private int stratumIndex = 0;
91private int currentFileId;
92
93private int defaultStratumIndex;
94private int baseStratumIndex;
95private char* sdePos;
96
97private char* jplsFilename = null;
98private char* NullString = null;
99
100/* mangled in parse, cannot be parsed. Must be kept. */
101private String sourceDebugExtension;
102
103private jboolean sourceMapIsValid;
104
105private jmp_buf jmp_buf_env;
106
107private int stratumTableIndex(String stratumId);
108private int stiLineTableIndex(int sti, int jplsLine);
109private int stiLineNumber(int sti, int lti, int jplsLine);
110private void decode(void);
111private void ignoreWhite(void);
112private jboolean isValid(void);
113
114 private void
115 loadDebugInfo(JNIEnv *env, jclass clazz) {
116
117 if (!isSameObject(env, clazz, cachedClass)) {
118 /* Not the same - swap out the info */
119
120 /* Delete existing info */
121 if ( cachedClass != null ) {
122 tossGlobalRef(env, &cachedClass);
123 cachedClass = null;
124 }
125 if ( sourceDebugExtension!=null ) {
126 jvmtiDeallocate(sourceDebugExtension);
127 }
128 sourceDebugExtension = null;
129
130 /* Init info */
131 lineTable = null;
132 fileTable = null;
133 stratumTable = null;
134 lineTableSize = 0;
135 fileTableSize = 0;
136 stratumTableSize = 0;
137 fileIndex = 0;
138 lineIndex = 0;
139 stratumIndex = 0;
140 currentFileId = 0;
141 defaultStratumId = null;
142 defaultStratumIndex = -1;
143 baseStratumIndex = -2; /* so as not to match -1 above */
144 sourceMapIsValid = false;
145
146 if (getSourceDebugExtension(clazz, &sourceDebugExtension) ==
147 JVMTI_ERROR_NONE) {
148 sdePos = sourceDebugExtension;
149 if (setjmp(jmp_buf_env) == 0) {
150 /* this is the initial (non-error) case, do parse */
151 decode();
152 }
153 }
154
155 cachedClass = null;
156 saveGlobalRef(env, clazz, &cachedClass);
157 }
158 }
159
160 /* Return 1 if match, 0 if no match */
161 private int
162 patternMatch(char *classname, const char *pattern) {
163 int pattLen;
164 int compLen;
165 char *start;
166 int offset;
167
168 if (pattern == NULL || classname == NULL) {
169 return 0;
170 }
171 pattLen = (int)strlen(pattern);
172
173 if ((pattern[0] != '*') && (pattern[pattLen-1] != '*')) {
174 return strcmp(pattern, classname) == 0;
175 }
176
177 compLen = pattLen - 1;
178 offset = (int)strlen(classname) - compLen;
179 if (offset < 0) {
180 return 0;
181 }
182 if (pattern[0] == '*') {
183 pattern++;
184 start = classname + offset;
185 } else {
186 start = classname;
187 }
188 return strncmp(pattern, start, compLen) == 0;
189 }
190
191 /**
192 * Return 1 if p1 is a SourceName for stratum sti,
193 * else, return 0.
194 */
195 private int
196 searchOneSourceName(int sti, char *p1) {
197 int fileIndexStart = stratumTable[sti].fileIndex;
198 /* one past end */
199 int fileIndexEnd = stratumTable[sti+1].fileIndex;
200 int ii;
201 for (ii = fileIndexStart; ii < fileIndexEnd; ++ii) {
202 if (patternMatch(fileTable[ii].sourceName, p1)) {
203 return 1;
204 }
205 }
206 return 0;
207 }
208
209 /**
210 * Return 1 if p1 is a SourceName for any stratum
211 * else, return 0.
212 */
213 int searchAllSourceNames(JNIEnv *env,
214 jclass clazz,
215 char *p1) {
216 int ii;
217 loadDebugInfo(env, clazz);
218 if (!isValid()) {
219 return 0; /* no SDE or not SourceMap */
220 }
221
222 for (ii = 0; ii < stratumIndex - 1; ++ii) {
223 if (searchOneSourceName(ii, p1) == 1) {
224 return 1;
225 }
226 }
227 return 0;
228 }
229
230 /**
231 * Convert a line number table, as returned by the JVMTI
232 * function GetLineNumberTable, to one for another stratum.
233 * Conversion is by overwrite.
234 * Actual line numbers are not returned - just a unique
235 * number (file ID in top 16 bits, line number in
236 * bottom 16 bits) - this is all stepping needs.
237 */
238 void
239 convertLineNumberTable(JNIEnv *env, jclass clazz,
240 jint *entryCountPtr,
241 jvmtiLineNumberEntry **tablePtr) {
242 jvmtiLineNumberEntry *fromEntry = *tablePtr;
243 jvmtiLineNumberEntry *toEntry = *tablePtr;
244 int cnt = *entryCountPtr;
245 int lastLn = 0;
246 int sti;
247
248 loadDebugInfo(env, clazz);
249 if (!isValid()) {
250 return; /* no SDE or not SourceMap - return unchanged */
251 }
252 sti = stratumTableIndex(globalDefaultStratumId);
253 if (sti == baseStratumIndex) {
254 return; /* Java stratum - return unchanged */
255 }
256 LOG_MISC(("SDE is re-ordering the line table"));
257 for (; cnt-->0; ++fromEntry) {
258 int jplsLine = fromEntry->line_number;
259 int lti = stiLineTableIndex(sti, jplsLine);
260 if (lti >= 0) {
261 int fileId = lineTable[lti].fileId;
262 int ln = stiLineNumber(sti, lti, jplsLine);
263 ln += (fileId << 16); /* create line hash */
264 if (ln != lastLn) {
265 lastLn = ln;
266 toEntry->start_location = fromEntry->start_location;
267 toEntry->line_number = ln;
268 ++toEntry;
269 }
270 }
271 }
272 /*LINTED*/
273 *entryCountPtr = (int)(toEntry - *tablePtr);
274 }
275
276 /**
277 * Set back-end wide default stratum ID .
278 */
279 void
280 setGlobalStratumId(char *id) {
281 globalDefaultStratumId = id;
282 }
283
284
285 private void syntax(String msg) {
286 char buf[200];
287 (void)snprintf(buf, sizeof(buf),
288 "bad SourceDebugExtension syntax - position %d - %s\n",
289 /*LINTED*/
290 (int)(sdePos-sourceDebugExtension),
291 msg);
292 JDI_ASSERT_FAILED(buf);
293
294 longjmp(jmp_buf_env, 1); /* abort parse */
295 }
296
297 private char sdePeek(void) {
298 if (*sdePos == 0) {
299 syntax("unexpected EOF");
300 }
301 return *sdePos;
302 }
303
304 private char sdeRead(void) {
305 if (*sdePos == 0) {
306 syntax("unexpected EOF");
307 }
308 return *sdePos++;
309 }
310
311 private void sdeAdvance(void) {
312 sdePos++;
313 }
314
315 private void assureLineTableSize(void) {
316 if (lineIndex >= lineTableSize) {
317 size_t allocSize;
318 LineTableRecord* new_lineTable;
319 int new_lineTableSize;
320
321 new_lineTableSize = lineTableSize == 0?
322 INIT_SIZE_LINE :
323 lineTableSize * 2;
324 allocSize = new_lineTableSize * (int)sizeof(LineTableRecord);
325 new_lineTable = jvmtiAllocate((jint)allocSize);
326 if ( new_lineTable == NULL ) {
327 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY, "SDE line table");
328 }
329 if ( lineTable!=NULL ) {
330 (void)memcpy(new_lineTable, lineTable,
331 lineTableSize * (int)sizeof(LineTableRecord));
332 jvmtiDeallocate(lineTable);
333 }
334 lineTable = new_lineTable;
335 lineTableSize = new_lineTableSize;
336 }
337 }
338
339 private void assureFileTableSize(void) {
340 if (fileIndex >= fileTableSize) {
341 size_t allocSize;
342 FileTableRecord* new_fileTable;
343 int new_fileTableSize;
344
345 new_fileTableSize = fileTableSize == 0?
346 INIT_SIZE_FILE :
347 fileTableSize * 2;
348 allocSize = new_fileTableSize * (int)sizeof(FileTableRecord);
349 new_fileTable = jvmtiAllocate((jint)allocSize);
350 if ( new_fileTable == NULL ) {
351 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY, "SDE file table");
352 }
353 if ( fileTable!=NULL ) {
354 (void)memcpy(new_fileTable, fileTable,
355 fileTableSize * (int)sizeof(FileTableRecord));
356 jvmtiDeallocate(fileTable);
357 }
358 fileTable = new_fileTable;
359 fileTableSize = new_fileTableSize;
360 }
361 }
362
363 private void assureStratumTableSize(void) {
364 if (stratumIndex >= stratumTableSize) {
365 size_t allocSize;
366 StratumTableRecord* new_stratumTable;
367 int new_stratumTableSize;
368
369 new_stratumTableSize = stratumTableSize == 0?
370 INIT_SIZE_STRATUM :
371 stratumTableSize * 2;
372 allocSize = new_stratumTableSize * (int)sizeof(StratumTableRecord);
373 new_stratumTable = jvmtiAllocate((jint)allocSize);
374 if ( new_stratumTable == NULL ) {
375 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY, "SDE stratum table");
376 }
377 if ( stratumTable!=NULL ) {
378 (void)memcpy(new_stratumTable, stratumTable,
379 stratumTableSize * (int)sizeof(StratumTableRecord));
380 jvmtiDeallocate(stratumTable);
381 }
382 stratumTable = new_stratumTable;
383 stratumTableSize = new_stratumTableSize;
384 }
385 }
386
387 private String readLine(void) {
388 char *initialPos;
389 char ch;
390
391 ignoreWhite();
392 initialPos = sdePos;
393 while (((ch = *sdePos) != '\n') && (ch != '\r')) {
394 if (ch == 0) {
395 syntax("unexpected EOF");
396 }
397 ++sdePos;
398 }
399 *sdePos++ = 0; /* null terminate string - mangles SDE */
400
401 /* check for CR LF */
402 if ((ch == '\r') && (*sdePos == '\n')) {
403 ++sdePos;
404 }
405 ignoreWhite(); /* leading white */
406 return initialPos;
407 }
408
409 private int defaultStratumTableIndex(void) {
410 if ((defaultStratumIndex == -1) && (defaultStratumId != null)) {
411 defaultStratumIndex =
412 stratumTableIndex(defaultStratumId);
413 }
414 return defaultStratumIndex;
415 }
416
417 private int stratumTableIndex(String stratumId) {
418 int i;
419
420 if (stratumId == null) {
421 return defaultStratumTableIndex();
422 }
423 for (i = 0; i < (stratumIndex-1); ++i) {
424 if (strcmp(stratumTable[i].id, stratumId) == 0) {
425 return i;
426 }
427 }
428 return defaultStratumTableIndex();
429 }
430
431
432/*****************************
433 * below functions/methods are written to compile under either Java or C
434 *
435 * Needed support functions:
436 * sdePeek()
437 * sdeRead()
438 * sdeAdvance()
439 * readLine()
440 * assureLineTableSize()
441 * assureFileTableSize()
442 * assureStratumTableSize()
443 * syntax(String)
444 *
445 * stratumTableIndex(String)
446 *
447 * Needed support variables:
448 * lineTable
449 * lineIndex
450 * fileTable
451 * fileIndex
452 * currentFileId
453 *
454 * Needed types:
455 * String
456 *
457 * Needed constants:
458 * NullString
459 */
460
461 private void ignoreWhite(void) {
462 char ch;
463
464 while (((ch = sdePeek()) == ' ') || (ch == '\t')) {
465 sdeAdvance();
466 }
467 }
468
469 private void ignoreLine(void) {
470 char ch;
471
472 do {
473 ch = sdeRead();
474 } while ((ch != '\n') && (ch != '\r'));
475
476 /* check for CR LF */
477 if ((ch == '\r') && (sdePeek() == '\n')) {
478 sdeAdvance();
479 }
480 ignoreWhite(); /* leading white */
481 }
482
483 private int readNumber(void) {
484 int value = 0;
485 char ch;
486
487 ignoreWhite();
488 while (((ch = sdePeek()) >= '0') && (ch <= '9')) {
489 sdeAdvance();
490 value = (value * 10) + ch - '0';
491 }
492 ignoreWhite();
493 return value;
494 }
495
496 private void storeFile(int fileId, String sourceName, String sourcePath) {
497 assureFileTableSize();
498 fileTable[fileIndex].fileId = fileId;
499 fileTable[fileIndex].sourceName = sourceName;
500 fileTable[fileIndex].sourcePath = sourcePath;
501 ++fileIndex;
502 }
503
504 private void fileLine(void) {
505 int hasAbsolute = 0; /* acts as boolean */
506 int fileId;
507 String sourceName;
508 String sourcePath = null;
509
510 /* is there an absolute filename? */
511 if (sdePeek() == '+') {
512 sdeAdvance();
513 hasAbsolute = 1;
514 }
515 fileId = readNumber();
516 sourceName = readLine();
517 if (hasAbsolute == 1) {
518 sourcePath = readLine();
519 }
520 storeFile(fileId, sourceName, sourcePath);
521 }
522
523 private void storeLine(int jplsStart, int jplsEnd, int jplsLineInc,
524 int njplsStart, int njplsEnd, int fileId) {
525 assureLineTableSize();
526 lineTable[lineIndex].jplsStart = jplsStart;
527 lineTable[lineIndex].jplsEnd = jplsEnd;
528 lineTable[lineIndex].jplsLineInc = jplsLineInc;
529 lineTable[lineIndex].njplsStart = njplsStart;
530 lineTable[lineIndex].njplsEnd = njplsEnd;
531 lineTable[lineIndex].fileId = fileId;
532 ++lineIndex;
533 }
534
535 /**
536 * Parse line translation info. Syntax is
537 * <NJ-start-line> [ # <file-id> ] [ , <line-count> ] :
538 * <J-start-line> [ , <line-increment> ] CR
539 */
540 private void lineLine(void) {
541 int lineCount = 1;
542 int lineIncrement = 1;
543 int njplsStart;
544 int jplsStart;
545
546 njplsStart = readNumber();
547
548 /* is there a fileID? */
549 if (sdePeek() == '#') {
550 sdeAdvance();
551 currentFileId = readNumber();
552 }
553
554 /* is there a line count? */
555 if (sdePeek() == ',') {
556 sdeAdvance();
557 lineCount = readNumber();
558 }
559
560 if (sdeRead() != ':') {
561 syntax("expected ':'");
562 }
563 jplsStart = readNumber();
564 if (sdePeek() == ',') {
565 sdeAdvance();
566 lineIncrement = readNumber();
567 }
568 ignoreLine(); /* flush the rest */
569
570 storeLine(jplsStart,
571 jplsStart + (lineCount * lineIncrement) -1,
572 lineIncrement,
573 njplsStart,
574 njplsStart + lineCount -1,
575 currentFileId);
576 }
577
578 /**
579 * Until the next stratum section, everything after this
580 * is in stratumId - so, store the current indicies.
581 */
582 private void storeStratum(String stratumId) {
583 /* remove redundant strata */
584 if (stratumIndex > 0) {
585 if ((stratumTable[stratumIndex-1].fileIndex
586 == fileIndex) &&
587 (stratumTable[stratumIndex-1].lineIndex
588 == lineIndex)) {
589 /* nothing changed overwrite it */
590 --stratumIndex;
591 }
592 }
593 /* store the results */
594 assureStratumTableSize();
595 stratumTable[stratumIndex].id = stratumId;
596 stratumTable[stratumIndex].fileIndex = fileIndex;
597 stratumTable[stratumIndex].lineIndex = lineIndex;
598 ++stratumIndex;
599 currentFileId = 0;
600 }
601
602 /**
603 * The beginning of a stratum's info
604 */
605 private void stratumSection(void) {
606 storeStratum(readLine());
607 }
608
609 private void fileSection(void) {
610 ignoreLine();
611 while (sdePeek() != '*') {
612 fileLine();
613 }
614 }
615
616 private void lineSection(void) {
617 ignoreLine();
618 while (sdePeek() != '*') {
619 lineLine();
620 }
621 }
622
623 /**
624 * Ignore a section we don't know about.
625 */
626 private void ignoreSection(void) {
627 ignoreLine();
628 while (sdePeek() != '*') {
629 ignoreLine();
630 }
631 }
632
633 /**
634 * A base "Java" stratum is always available, though
635 * it is not in the SourceDebugExtension.
636 * Create the base stratum.
637 */
638 private void createJavaStratum(void) {
639 baseStratumIndex = stratumIndex;
640 storeStratum(BASE_STRATUM_NAME);
641 storeFile(1, jplsFilename, NullString);
642 /* JPL line numbers cannot exceed 65535 */
643 storeLine(1, 65536, 1, 1, 65536, 1);
644 storeStratum("Aux"); /* in case they don't declare */
645 }
646
647 /**
648 * Decode a SourceDebugExtension which is in SourceMap format.
649 * This is the entry point into the recursive descent parser.
650 */
651 private void decode(void) {
652 /* check for "SMAP" - allow EOF if not ours */
653 if (strlen(sourceDebugExtension) <= 4 ||
654 (sdeRead() != 'S') ||
655 (sdeRead() != 'M') ||
656 (sdeRead() != 'A') ||
657 (sdeRead() != 'P')) {
658 return; /* not our info */
659 }
660 ignoreLine(); /* flush the rest */
661 jplsFilename = readLine();
662 defaultStratumId = readLine();
663 createJavaStratum();
664 while (true) {
665 if (sdeRead() != '*') {
666 syntax("expected '*'");
667 }
668 switch (sdeRead()) {
669 case 'S':
670 stratumSection();
671 break;
672 case 'F':
673 fileSection();
674 break;
675 case 'L':
676 lineSection();
677 break;
678 case 'E':
679 /* set end points */
680 storeStratum("*terminator*");
681 sourceMapIsValid = true;
682 return;
683 default:
684 ignoreSection();
685 }
686 }
687 }
688
689 /***************** query functions ***********************/
690
691 private int stiLineTableIndex(int sti, int jplsLine) {
692 int i;
693 int lineIndexStart;
694 int lineIndexEnd;
695
696 lineIndexStart = stratumTable[sti].lineIndex;
697 /* one past end */
698 lineIndexEnd = stratumTable[sti+1].lineIndex;
699 for (i = lineIndexStart; i < lineIndexEnd; ++i) {
700 if ((jplsLine >= lineTable[i].jplsStart) &&
701 (jplsLine <= lineTable[i].jplsEnd)) {
702 return i;
703 }
704 }
705 return -1;
706 }
707
708 private int stiLineNumber(int sti, int lti, int jplsLine) {
709 return lineTable[lti].njplsStart +
710 (((jplsLine - lineTable[lti].jplsStart) /
711 lineTable[lti].jplsLineInc));
712 }
713
714 private int fileTableIndex(int sti, int fileId) {
715 int i;
716 int fileIndexStart = stratumTable[sti].fileIndex;
717 /* one past end */
718 int fileIndexEnd = stratumTable[sti+1].fileIndex;
719 for (i = fileIndexStart; i < fileIndexEnd; ++i) {
720 if (fileTable[i].fileId == fileId) {
721 return i;
722 }
723 }
724 return -1;
725 }
726
727 private int stiFileTableIndex(int sti, int lti) {
728 return fileTableIndex(sti, lineTable[lti].fileId);
729 }
730
731 private jboolean isValid(void) {
732 return sourceMapIsValid;
733 }