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