1 /* 2 * Copyright (c) 2001, 2008, 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 */ 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(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 }