diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2023-03-22 12:04:33 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-22 12:04:33 -0400 |
| commit | d4f99c8bac8b28f18c864a717d8833db6a1c872d (patch) | |
| tree | ebea06c019130d8248d5e4f6bccf5e4b2649e3cb /source | |
| parent | d8a40abba5223fbcb56c52b04ccb88c02bbaf79f (diff) | |
Source map obfuscation (#2717)
* #include an absolute path didn't work - because paths were taken to always be relative.
* WIP source map.
* Split out handling of RttiTypeFuncs to a map type.
* Make RttiTypeFuncsMap hold default impls.
* Slightly more sophisticated RttiTypeFuncsMap
* Source map decoding.
* Fix tabs.
* Fix asserts due to negative values.
* Use less obscure mechanisms in SourceMap.
* Source map decoding.
Simplifying SourceMap usage.
* First attempt at ouputting a source map as part of emit.
* Added support for -source-map option. SourceMap is added to the artifact.
* Small improvements around column calculation in SourceWriter.
* Source Loc obuscation WIP.
* Fix some issues around SourceMap obfuscation.
* Split out obfuscation into its own file.
* Keep obfuscated SourceMap even through serialization bottleneck.
Diffstat (limited to 'source')
| -rw-r--r-- | source/compiler-core/slang-artifact-desc-util.cpp | 7 | ||||
| -rw-r--r-- | source/compiler-core/slang-artifact.h | 6 | ||||
| -rw-r--r-- | source/compiler-core/slang-source-loc.cpp | 29 | ||||
| -rw-r--r-- | source/compiler-core/slang-source-loc.h | 20 | ||||
| -rw-r--r-- | source/core/slang-char-encode.cpp | 34 | ||||
| -rw-r--r-- | source/core/slang-char-encode.h | 10 | ||||
| -rw-r--r-- | source/core/slang-char-util.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-emit-source-writer.cpp | 83 | ||||
| -rw-r--r-- | source/slang/slang-emit.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-ir-obfuscate-loc.cpp | 279 | ||||
| -rw-r--r-- | source/slang/slang-ir-obfuscate-loc.h | 20 | ||||
| -rw-r--r-- | source/slang/slang-ir.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 23 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 4 |
14 files changed, 466 insertions, 61 deletions
diff --git a/source/compiler-core/slang-artifact-desc-util.cpp b/source/compiler-core/slang-artifact-desc-util.cpp index ee014daf0..08b7c8412 100644 --- a/source/compiler-core/slang-artifact-desc-util.cpp +++ b/source/compiler-core/slang-artifact-desc-util.cpp @@ -175,6 +175,7 @@ bool isDerivedFrom(ENUM_TYPE kind, ENUM_TYPE base) { return g_table##ENUM_TYPE.i x(HumanText, Text) \ x(Source, Text) \ x(Assembly, Text) \ + x(Json, Text) \ x(Instance, Base) #define SLANG_ARTIFACT_KIND_ENTRY(TYPE, PARENT) { Index(ArtifactKind::TYPE), Index(ArtifactKind::PARENT), #TYPE }, @@ -239,13 +240,13 @@ SLANG_HIERARCHICAL_ENUM(ArtifactPayload, SLANG_ARTIFACT_PAYLOAD, SLANG_ARTIFACT_ x(Unknown, Base) \ x(CodeLike, Base) \ x(Kernel, CodeLike) \ - x(Host, CodeLike) + x(Host, CodeLike) \ + x(Obfuscated, Base) #define SLANG_ARTIFACT_STYLE_ENTRY(TYPE, PARENT) { Index(ArtifactStyle::TYPE), Index(ArtifactStyle::PARENT), #TYPE }, SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYLE_ENTRY) - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDescUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ /* static */ArtifactDesc ArtifactDescUtil::makeDescForCompileTarget(SlangCompileTarget target) @@ -555,7 +556,7 @@ static const KindExtension g_cpuKindExts[] = // Visual Studio. It's used here for source map. if (slice == toSlice("map")) { - return ArtifactDesc::make(ArtifactKind::Text, ArtifactPayload::SourceMap); + return ArtifactDesc::make(ArtifactKind::Json, ArtifactPayload::SourceMap); } if (slice == toSlice("pdb")) diff --git a/source/compiler-core/slang-artifact.h b/source/compiler-core/slang-artifact.h index c51ee729a..cc4d3e9fd 100644 --- a/source/compiler-core/slang-artifact.h +++ b/source/compiler-core/slang-artifact.h @@ -107,6 +107,8 @@ enum class ArtifactKind : uint8_t Instance, ///< Primary representation is an interface/class instance + Json, ///< It's JSON + CountOf, }; @@ -180,7 +182,7 @@ enum class ArtifactPayload : uint8_t PdbDebugInfo, ///< PDB debug info - SourceMap, ///< SourceMap + SourceMap, ///< A source map CountOf, }; @@ -207,6 +209,8 @@ enum class ArtifactStyle : uint8_t Kernel, ///< Compiled as `GPU kernel` style. Host, ///< Compiled in `host` style + Obfuscated, ///< Holds something specific to obfuscation, such as an obfuscated source map + CountOf, }; diff --git a/source/compiler-core/slang-source-loc.cpp b/source/compiler-core/slang-source-loc.cpp index 95c6f5db3..1314d8066 100644 --- a/source/compiler-core/slang-source-loc.cpp +++ b/source/compiler-core/slang-source-loc.cpp @@ -189,7 +189,7 @@ void SourceView::addDefaultLineDirective(SourceLoc directiveLoc) m_entries.add(entry); } -HumaneSourceLoc SourceView::getHumaneLoc(SourceLoc loc, SourceLocType type) +HandleSourceLoc SourceView::getHandleLoc(SourceLoc loc, SourceLocType type) { const int offset = m_range.getOffset(loc); @@ -206,9 +206,9 @@ HumaneSourceLoc SourceView::getHumaneLoc(SourceLoc loc, SourceLocType type) // that an IDE expects us to use when reporting locations?) const int columnIndex = m_sourceFile->calcColumnIndex(lineIndex, offset); - HumaneSourceLoc humaneLoc; - humaneLoc.column = columnIndex + 1; - humaneLoc.line = lineIndex + 1; + HandleSourceLoc handleLoc; + handleLoc.column = columnIndex + 1; + handleLoc.line = lineIndex + 1; // Make up a default entry StringSlicePool::Handle pathHandle = StringSlicePool::Handle(0); @@ -219,16 +219,27 @@ HumaneSourceLoc SourceView::getHumaneLoc(SourceLoc loc, SourceLocType type) { const Entry& entry = m_entries[entryIndex]; // Adjust the line - humaneLoc.line += entry.m_lineAdjust; + handleLoc.line += entry.m_lineAdjust; // Get the pathHandle.. pathHandle = entry.m_pathHandle; } - humaneLoc.pathInfo = _getPathInfoFromHandle(pathHandle); + handleLoc.pathHandle = pathHandle; + return handleLoc; +} + +HumaneSourceLoc SourceView::getHumaneLoc(SourceLoc loc, SourceLocType type) +{ + HandleSourceLoc handleLoc = getHandleLoc(loc, type); + + HumaneSourceLoc humaneLoc; + humaneLoc.column = handleLoc.column; + humaneLoc.line = handleLoc.line; + humaneLoc.pathInfo = _getPathInfoFromHandle(handleLoc.pathHandle); return humaneLoc; } -PathInfo SourceView::_getPathInfo() const +PathInfo SourceView::getViewPathInfo() const { if (m_viewPath.getLength()) { @@ -247,7 +258,7 @@ PathInfo SourceView::_getPathInfoFromHandle(StringSlicePool::Handle pathHandle) // If there is no override path, then just the source files path if (pathHandle == StringSlicePool::Handle(0)) { - return _getPathInfo(); + return getViewPathInfo(); } else { @@ -259,7 +270,7 @@ PathInfo SourceView::getPathInfo(SourceLoc loc, SourceLocType type) { if (type == SourceLocType::Actual) { - return _getPathInfo(); + return getViewPathInfo(); } const int entryIndex = findEntryIndex(loc); diff --git a/source/compiler-core/slang-source-loc.h b/source/compiler-core/slang-source-loc.h index 66e4c0475..15c7c0a53 100644 --- a/source/compiler-core/slang-source-loc.h +++ b/source/compiler-core/slang-source-loc.h @@ -279,6 +279,13 @@ struct HumaneSourceLoc Int column = 0; }; +// Same as HumaneSourceLoc but stores the path only as a handle. +struct HandleSourceLoc +{ + StringSlicePool::Handle pathHandle = StringSlicePool::Handle(0); + Int line = 0; + Int column = 0; +}; /* A SourceView maps to a single span of SourceLoc range and is equivalent to a single include or more precisely use of a source file. It is distinct from a SourceFile - because a SourceFile may be included multiple times, with different interpretations (depending @@ -336,6 +343,10 @@ class SourceView /// Type determines if the location wanted is the original, or the 'normal' (which modifys behavior based on #line directives) HumaneSourceLoc getHumaneLoc(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); + /// Get the humane location, but store the path as a handle + HandleSourceLoc getHandleLoc(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); + + /// Get the path associated with a location PathInfo getPathInfo(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); @@ -346,6 +357,10 @@ class SourceView /// For the original source file (ie not an include) - the view will have an initiating source loc of SourceLoc(0) SourceLoc getInitiatingSourceLoc() const { return m_initiatingSourceLoc; } + /// Gets the pathInfo for this view. It may be different from the m_sourceFile's if the path has been + /// overridden by m_viewPath + PathInfo getViewPathInfo() const; + /// Ctor SourceView(SourceFile* sourceFile, SourceRange range, const String* viewPath, SourceLoc initiatingSourceLoc): m_range(range), @@ -361,10 +376,7 @@ class SourceView protected: /// Get the pathInfo from a string handle. If it's 0, it will return the _getPathInfo PathInfo _getPathInfoFromHandle(StringSlicePool::Handle pathHandle) const; - /// Gets the pathInfo for this view. It may be different from the m_sourceFile's if the path has been - /// overridden by m_viewPath - PathInfo _getPathInfo() const; - + String m_viewPath; ///< Path to this view. If empty the path is the path to the SourceView SourceLoc m_initiatingSourceLoc; ///< An optional source loc that defines where this view was initiated from. SourceLoc(0) if not defined. diff --git a/source/core/slang-char-encode.cpp b/source/core/slang-char-encode.cpp index d061e34ba..687040fa2 100644 --- a/source/core/slang-char-encode.cpp +++ b/source/core/slang-char-encode.cpp @@ -178,4 +178,38 @@ CharEncoding* CharEncoding::UTF16 = &_utf16Encoding; CharEncoding* CharEncoding::UTF16Reversed = &_utf16EncodingReversed; CharEncoding* CharEncoding::UTF32 = &_utf32Encoding; +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UTF8Util !!!!!!!!!!!!!!!!!!!!!!!!! */ + +/* static */Index UTF8Util::calcCodePointCount(const UnownedStringSlice& in) +{ + Index count = 0; + + // Analyse with bytes... + const int8_t* cur = (const int8_t*)in.begin(); + const int8_t*const end = (const int8_t*)in.end(); + + while (cur < end) + { + const auto c = *cur++; + + count++; + + // If c < 0 it means the top bit is set... which means we have multiple bytes + if (c < 0) + { + // https://en.wikipedia.org/wiki/UTF-8 + // All continuation bytes contain exactly six bits from the code point.So the next six bits of the code point + /// are stored in the low order six bits of the next byte, and 10 is stored in the high order two bits to + // mark it as a continuation byte(so 10000010). + + while (cur < end && (*cur & 0xc0) == 0x80) + { + cur++; + } + } + } + + return count; +} + } // namespace Slang diff --git a/source/core/slang-char-encode.h b/source/core/slang-char-encode.h index a778cc3c9..2bb4cba29 100644 --- a/source/core/slang-char-encode.h +++ b/source/core/slang-char-encode.h @@ -195,6 +195,16 @@ protected: static CharEncoding*const g_encoding[Index(CharEncodeType::CountOf)]; }; +struct UTF8Util +{ + /// Given a slice calculate the number of code points (unicode chars) + /// + /// NOTE! This doesn't check the *validity* of code points/encoding. + /// Non valid utf8 input or ending starting in partial characters, will produce + /// undefined results without error. + static Index calcCodePointCount(const UnownedStringSlice& in); +}; + } #endif diff --git a/source/core/slang-char-util.h b/source/core/slang-char-util.h index 40abee602..1ed8f7f73 100644 --- a/source/core/slang-char-util.h +++ b/source/core/slang-char-util.h @@ -47,6 +47,9 @@ struct CharUtil /// Given a character return the upper case equivalent SLANG_FORCE_INLINE static char toUpper(char c) { return (c >= 'a' && c <= 'z') ? (c -'a' + 'A') : c; } + /// Given a value between 0-15 inclusive returns the hex digit. Uses lower case hex. + SLANG_FORCE_INLINE static char getHexChar(Index i) { SLANG_ASSERT((i & ~Index(0xf)) == 0); return char(i >= 10 ? (i - 10 + 'a') : (i + '0')); } + /// Returns the value if c interpretted as a hex digit /// If c is not a valid hex returns -1 inline static int getHexDigitValue(char c); diff --git a/source/slang/slang-emit-source-writer.cpp b/source/slang/slang-emit-source-writer.cpp index b27e0f8b4..f66f36758 100644 --- a/source/slang/slang-emit-source-writer.cpp +++ b/source/slang/slang-emit-source-writer.cpp @@ -1,6 +1,8 @@ // slang-emit-source-writer.cpp #include "slang-emit-source-writer.h" +#include "../core/slang-char-encode.h" + // Disable warnings about sprintf #ifdef _WIN32 # pragma warning(disable:4996) @@ -516,61 +518,60 @@ void SourceWriter::_emitLineDirective(const HumaneSourceLoc& sourceLocation) void SourceWriter::_calcLocation(Index& outLineIndex, Index& outColumnIndex) { - // If we are at the end, then we are done. - if (m_currentOutputOffset == m_builder.getLength()) - { - outLineIndex = m_currentLineIndex; - outColumnIndex = m_currentColumnIndex; - return; - } - - const char* cur = m_builder.getBuffer() + m_currentOutputOffset; - const char* end = m_builder.end(); - - const char* start = cur; - - while (cur < end) + // If there are move chars we need to update + if (m_currentOutputOffset < m_builder.getLength()) { - // Reset start - start = cur; + const char* cur = m_builder.getBuffer() + m_currentOutputOffset; + const char* end = m_builder.end(); - // Look for the end of the line - while (*cur != '\n' && *cur != '\r' && cur < end) - { - cur++; - } + const char* start = cur; - // If we are not at the total end then we must have hit a \n or \r - if (cur < end) + while (cur < end) { - const auto c = *cur++; + // Reset start + start = cur; - ++m_currentLineIndex; - // Reset the column - m_currentColumnIndex = 0; + // Look for the end of the line + while (*cur != '\n' && *cur != '\r' && cur < end) + { + cur++; + } - // Check the next char to see if it's part of a CR/LF combination + // If we are not at the total end then we must have hit a \n or \r if (cur < end) { - const auto d = *cur; - // If it is combination skip the next byte - cur += ((c ^ d) == ('\r' ^ '\n')); + const auto c = *cur++; + + // Next line + ++m_currentLineIndex; + + // Check the next char to see if it's part of a CR/LF combination + if (cur < end) + { + const auto d = *cur; + // If it is combination skip the next byte + cur += ((c ^ d) == ('\r' ^ '\n')); + } + + // Calculate the offset to the start of this line + m_currentColumnIndex = 0; + start = cur; } } - } - // Fix up the current index. - // TODO(JS): - // NOTE! This isn't strictly correct because it assumes one byte is a *column* which isn't actually the case with utf8 - // encoding... - m_currentColumnIndex += Index(cur - start); + // Set the current offset to the end + m_currentOutputOffset = m_builder.getLength(); - // Set the current offset is the end - m_currentOutputOffset = m_builder.getLength(); + // Get the bytes remaining on this line (which may not be complete) + const UnownedStringSlice lineRemaining(start, m_builder.end()); - // Output the values - outLineIndex = m_currentLineIndex; + // Offset the column index in codepoints + m_currentColumnIndex += UTF8Util::calcCodePointCount(lineRemaining); + } + + // Output the position outColumnIndex = m_currentColumnIndex; + outLineIndex = m_currentLineIndex; } } // namespace Slang diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 335e95c9e..bc62e488f 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -1126,7 +1126,7 @@ SlangResult CodeGenContext::emitEntryPointsSourceFromIR(ComPtr<IArtifact>& outAr auto sourceMapBlob = StringBlob::moveCreate(writer.getBuilder()); - auto sourceMapArtifact = ArtifactUtil::createArtifact(ArtifactDesc::make(ArtifactKind::Text, ArtifactPayload::SourceMap, ArtifactStyle::None)); + auto sourceMapArtifact = ArtifactUtil::createArtifact(ArtifactDesc::make(ArtifactKind::Json, ArtifactPayload::SourceMap, ArtifactStyle::None)); sourceMapArtifact->addRepresentationUnknown(sourceMapBlob); artifact->addAssociated(sourceMapArtifact); diff --git a/source/slang/slang-ir-obfuscate-loc.cpp b/source/slang/slang-ir-obfuscate-loc.cpp new file mode 100644 index 000000000..b3f5d5cd3 --- /dev/null +++ b/source/slang/slang-ir-obfuscate-loc.cpp @@ -0,0 +1,279 @@ +// slang-ir-obfuscate-loc.cpp +#include "slang-ir-obfuscate-loc.h" + +#include "../../slang.h" + +#include "../core/slang-random-generator.h" +#include "../core/slang-hash.h" +#include "../core/slang-char-util.h" + +namespace Slang +{ + +namespace { // anonymous + +struct InstWithLoc +{ + typedef InstWithLoc ThisType; + + SLANG_FORCE_INLINE bool operator<(const ThisType& rhs) const { return loc.getRaw() < rhs.loc.getRaw(); } + + IRInst* inst; + SourceLoc loc; +}; + +struct LocPair +{ + SourceLoc originalLoc; + SourceLoc obfuscatedLoc; +}; + +} // anonymous + +static void _findInstsRec(IRInst* inst, List<InstWithLoc>& out) +{ + if (inst->sourceLoc.isValid()) + { + InstWithLoc instWithLoc; + instWithLoc.inst = inst; + instWithLoc.loc = inst->sourceLoc; + out.add(instWithLoc); + } + + for (IRInst* child : inst->getModifiableChildren()) + { + _findInstsRec(child, out); + } +} + +SlangResult obfuscateModuleLocs(IRModule* module, SourceManager* sourceManager) +{ + // There shouldn't be an obfuscated source map set + SLANG_ASSERT(module->getObfuscatedSourceMap() == nullptr); + + List<InstWithLoc> instWithLocs; + + // Find all of the instructions with source locs + _findInstsRec(module->getModuleInst(), instWithLocs); + + // Sort them + instWithLocs.sort(); + + // Lets produce a hash, so we can use as a key for random number generation. + // We could base it on time, or some other thing as there is no requirement for + // stability or consistency. + // We use a hash because it avoids issues around clocks, and availability of a clock + // as a good source of entropy. + // + // An argument *could* be made to generate the name via some mechanism that uniquely identified the + // combination of flags, options, files, names that identified the compilation, but that is + // not easily achieved. + HashCode hash = 0; + + List<LocPair> locPairs; + + { + SourceLoc curLoc; + for (const auto& instWithLoc : instWithLocs) + { + hash = combineHash(hash, getHashCode(instWithLoc.inst)); + hash = combineHash(hash, getHashCode(instWithLoc.loc.getRaw())); + + if (instWithLoc.loc != curLoc) + { + LocPair locPair; + locPair.originalLoc = instWithLoc.loc; + locPairs.add(locPair); + + // This is the current loc + curLoc = instWithLoc.loc; + } + } + } + + const Count uniqueLocCount = locPairs.getCount(); + + // We need a seed to make this random on each run + const uint32_t randomSeed = uint32_t(hash); + RefPtr<RandomGenerator> rand = RandomGenerator::create(randomSeed); + + // We want a random unique name because we could have multiple obfuscated modules + // and we need to identify each + + PathInfo obfusctatedPathInfo; + + { + // We need a pathInfo to *identify* this modules obfuscated locs. + // We are going to use a random number, seeded from the hash to do this. + // Turning the number as hex as the name. + { + StringBuilder buf; + + uint8_t data[4]; + rand->nextData(data, sizeof(data)); + + const Count charsCount = SLANG_COUNT_OF(data) * 2; + + char* dst = buf.prepareForAppend(charsCount); + + for (Index i = 0; i < SLANG_COUNT_OF(data); ++i) + { + dst[i * 2 + 0] = CharUtil::getHexChar(data[i] & 0xf); + dst[i * 2 + 1] = CharUtil::getHexChar(data[i] >> 4); + } + buf.appendInPlace(dst, charsCount); + obfusctatedPathInfo = PathInfo::makePath(buf); + } + } + + SourceFile* obfuscatedFile = sourceManager->createSourceFileWithSize(obfusctatedPathInfo, uniqueLocCount); + + // Create the view we are going to use from the obfusctated "file". + SourceView* obfuscatedView = sourceManager->createSourceView(obfuscatedFile, nullptr, SourceLoc()); + + // Okay now we want to produce a map from these locs to a new source location + { + // Create a "bag" and put all of the indices in it. + List<SourceLoc> bag; + + bag.setCount(uniqueLocCount); + + const SourceLoc baseLoc = obfuscatedView->getRange().begin; + + { + SourceLoc* dst = bag.getBuffer(); + for (Index i = 0; i < uniqueLocCount; ++i) + { + dst[i] = baseLoc + i; + } + } + + // Pull the indices randomly out of the bag to create the map + for (auto& pair : locPairs) + { + // Find an index in the bag + const Index bagIndex = rand->nextInt32InRange(0, int32_t(bag.getCount())); + // Set in the map + pair.obfuscatedLoc = bag[bagIndex]; + // Remove from the bag + bag.fastRemoveAt(bagIndex); + } + } + + // We can now just set all the new locs in the instructions + { + const LocPair* curPair = locPairs.getBuffer(); + LocPair pair = *curPair; + + for (const auto& instWithLoc : instWithLocs) + { + auto inst = instWithLoc.inst; + + if (instWithLoc.loc != pair.originalLoc) + { + SLANG_ASSERT(curPair < locPairs.end()); + curPair++; + pair = *curPair; + } + SLANG_ASSERT(pair.originalLoc == instWithLoc.loc); + + // Set the loc + inst->sourceLoc = pair.obfuscatedLoc; + } + } + + // We can now create a map. The locs are in order in entries, so that should make lookup easier. + // This doesn't "leak" anything as the obfuscated loc map is not distributed. + + RefPtr<SourceMap> sourceMap = new SourceMap; + sourceMap->m_file = obfusctatedPathInfo.getName(); + + // Make sure we have line 0. + // We only end up with one line in the obfuscated map. + sourceMap->advanceToLine(0); + + { + // Current view, with cached "View" based sourceFileIndex + SourceView* curView = nullptr; + Index curViewSourceFileIndex = -1; + + // Current handle, and store cached index in curPathSourceFileIndex + StringSlicePool::Handle curPathHandle = StringSlicePool::Handle(0); + Index curPathSourceFileIndex = -1; + + for (Index i = 0; i < uniqueLocCount; ++i) + { + const auto& pair = locPairs[i]; + + + // First find the view + if (curView == nullptr || + !curView->getRange().contains(pair.originalLoc)) + { + curView = sourceManager->findSourceViewRecursively(pair.originalLoc); + SLANG_ASSERT(curView); + + // Reset the current view path index, to being unset + curViewSourceFileIndex = -1; + + // We have to reset, because the path index is for the source manager + // that holds the view. If the view changes we need to re determine the + // path string, and index. + curPathSourceFileIndex = -1; + } + + // Now get the location + const auto handleLoc = curView->getHandleLoc(pair.originalLoc); + + Index sourceFileIndex = -1; + + if (handleLoc.pathHandle == StringSlicePool::Handle(0)) + { + if (curViewSourceFileIndex < 0) + { + const auto pathInfo = curView->getViewPathInfo(); + curViewSourceFileIndex = sourceMap->getSourceFileIndex(pathInfo.getName().getUnownedSlice()); + } + sourceFileIndex = curViewSourceFileIndex; + } + else + { + if (curPathSourceFileIndex < 0 || + handleLoc.pathHandle != curPathHandle) + { + auto viewSourceManager = curView->getSourceManager(); + const auto filePathSlice = viewSourceManager->getStringSlicePool().getSlice(curPathHandle); + + // Set the handle + curPathHandle = handleLoc.pathHandle; + + // Get the source file index. + curPathSourceFileIndex = sourceMap->getSourceFileIndex(filePathSlice); + } + + sourceFileIndex = curPathSourceFileIndex; + } + + // Create the entry + SourceMap::Entry entry; + entry.init(); + + entry.sourceFileIndex = sourceFileIndex; + + // i is the generated column + entry.generatedColumn = i; + + entry.sourceColumn = handleLoc.column - 1; + entry.sourceLine = handleLoc.line - 1; + + // Add it to the source map + sourceMap->addEntry(entry); + } + } + + module->setObfuscatedSourceMap(sourceMap); + + return SLANG_OK; +} + +} // namespace Slang diff --git a/source/slang/slang-ir-obfuscate-loc.h b/source/slang/slang-ir-obfuscate-loc.h new file mode 100644 index 000000000..03e32a143 --- /dev/null +++ b/source/slang/slang-ir-obfuscate-loc.h @@ -0,0 +1,20 @@ +// slang-ir-obfuscate-loc.h +#ifndef SLANG_IR_OBFUSCATE_LOC_H_INCLUDED +#define SLANG_IR_OBFUSCATE_LOC_H_INCLUDED + +#include "../core/slang-basic.h" + +#include "../compiler-core/slang-source-map.h" + +#include "slang-compiler.h" +#include "slang-ir.h" + +namespace Slang +{ + +/*** Obfuscate locs in module. Store the mapping from obfuscated locs to actual locs in the form of a source map */ +SlangResult obfuscateModuleLocs(IRModule* module, SourceManager* sourceManager); + +} + +#endif diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index 14a216fd2..025812f83 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -13,6 +13,7 @@ #include "../core/slang-memory-arena.h" #include "../compiler-core/slang-source-loc.h" +#include "../compiler-core/slang-source-map.h" #include "slang-type-system-shared.h" @@ -2008,6 +2009,9 @@ public: SLANG_FORCE_INLINE IRModuleInst* getModuleInst() const { return m_moduleInst; } SLANG_FORCE_INLINE MemoryArena& getMemoryArena() { return m_memoryArena; } + SLANG_FORCE_INLINE SourceMap* getObfuscatedSourceMap() const { return m_obfuscatedSourceMap; } + SLANG_FORCE_INLINE void setObfuscatedSourceMap(SourceMap* sourceMap) { m_obfuscatedSourceMap = sourceMap; } + IRDeduplicationContext* getDeduplicationContext() const { return &m_deduplicationContext; } IRInstListBase getGlobalInsts() const { return getModuleInst()->getChildren(); } @@ -2074,6 +2078,9 @@ private: /// Shared contexts for constructing and deduplicating the IR. mutable IRDeduplicationContext m_deduplicationContext; + + /// Holds the obfuscated source map for this module if applicable + RefPtr<SourceMap> m_obfuscatedSourceMap; }; struct IRSpecializationDictionaryItem : public IRInst diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 86df89702..f84f17886 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -3,6 +3,10 @@ #include "../../slang.h" +#include "../core/slang-random-generator.h" +#include "../core/slang-hash.h" +#include "../core/slang-char-util.h" + #include "slang-check.h" #include "slang-ir.h" #include "slang-ir-constexpr.h" @@ -21,6 +25,8 @@ #include "slang-ir-string-hash.h" #include "slang-ir-clone.h" #include "slang-ir-lower-error-handling.h" +#include "slang-ir-obfuscate-loc.h" + #include "slang-mangle.h" #include "slang-type-layout.h" #include "slang-visitor.h" @@ -9299,10 +9305,17 @@ RefPtr<IRModule> generateIRForTranslationUnit( Linkage* linkage = compileRequest->getLinkage(); stripOptions.shouldStripNameHints = linkage->m_obfuscateCode; - stripOptions.stripSourceLocs = linkage->m_obfuscateCode; + // If we are generating an obfuscated source map, we don't want to strip locs, + // we want to generate *new* locs that can be mapped (via source map) + // back to *actual* source. + // + // We don't do the obfuscation remapping here, because DCE and other passes may + // change what locs are actually needed, we need to be sure + // that if we have obfuscation enabled we don't forget to obfuscate. + stripOptions.stripSourceLocs = linkage->m_obfuscateCode && !linkage->m_generateSourceMap; stripFrontEndOnlyInstructions(module, stripOptions); - + // Stripping out decorations could leave some dead code behind // in the module, and in some cases that extra code is also // undesirable (e.g., the string literals referenced by name-hint @@ -9314,6 +9327,12 @@ RefPtr<IRModule> generateIRForTranslationUnit( IRDeadCodeEliminationOptions options; options.keepExportsAlive = true; eliminateDeadCode(module, options); + + if (linkage->m_obfuscateCode && linkage->m_generateSourceMap) + { + // The obfuscated source map is stored on the module + obfuscateModuleLocs(module, compileRequest->getSourceManager()); + } } // TODO: consider doing some more aggressive optimizations diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 14b59d156..bd19670d9 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -2377,6 +2377,9 @@ void FrontEndCompileRequest::generateIR() if (useSerialIRBottleneck) { + // Keep the obfuscated source map (if there is one) + RefPtr<SourceMap> obfuscatedSourceMap = irModule->getObfuscatedSourceMap(); + IRSerialData serialData; { // Write IR out to serialData - copying over SourceLoc information directly @@ -2395,6 +2398,7 @@ void FrontEndCompileRequest::generateIR() // Set irModule to the read module irModule = irReadModule; + irModule->setObfuscatedSourceMap(obfuscatedSourceMap); } // Set the module on the translation unit |
