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