internal void Encode(DebugInfoBlob blob) { blob.WriteDWORD(Timestamp); blob.WriteDWORD(AssemblyIndex & 0x7FFFFFFF | (HasPDB ? 0x80000000 : 0)); blob.WriteBuffer(VersionInfo, 0, VersionInfoLength); string nameWithPublicKey = Name; if (PublicKey != null && PublicKey.Length > 0) { nameWithPublicKey += ", PublicKey="; nameWithPublicKey += BitConverter.ToString(PublicKey).Replace("-", ""); } blob.WriteString(nameWithPublicKey); blob.AlignToDWORD(); }
private void Add_DEBUG_S_FUNC_MDTOKEN_MAP_Entry(DebugInfoBlob methodRVAToTokenMap, List <Relocation> debugRelocations, IMethodBodyNode method, uint methodDataOrOffsetToMethodData, ref uint entryCount) { debugRelocations.Add(new Relocation(RelocType.IMAGE_REL_BASED_ADDR32NB, checked ((int)methodRVAToTokenMap.Size()), method)); methodRVAToTokenMap.WriteDWORD(0); methodRVAToTokenMap.WriteDWORD(methodDataOrOffsetToMethodData); entryCount++; IMethodBodyNodeWithFuncletSymbols funcletSymbolsNode = method as IMethodBodyNodeWithFuncletSymbols; if (funcletSymbolsNode != null) { foreach (ISymbolNode funclet in funcletSymbolsNode.FuncletSymbols) { debugRelocations.Add(new Relocation(RelocType.IMAGE_REL_BASED_ADDR32NB, checked ((int)methodRVAToTokenMap.Size()), funclet)); methodRVAToTokenMap.WriteDWORD(0); methodRVAToTokenMap.WriteDWORD(methodDataOrOffsetToMethodData); entryCount++; } } }
private DebugInfoBlob ConvertToDebugInfoBlob(List <SortedDictionary <uint, int> > assemblyMethods) { DebugInfoBlob debugInfoBlob = new DebugInfoBlob(); // version debugInfoBlob.WriteDWORD(0); // number of assemblies debugInfoBlob.WriteDWORD((uint)assemblyMethods.Count); foreach (var methods in assemblyMethods) { debugInfoBlob.WriteDWORD((uint)methods.Count); foreach (var method in methods) { // method token debugInfoBlob.WriteDWORD(method.Key); // method info length , now it's 4 debugInfoBlob.WriteWORD(4); // method slot debugInfoBlob.WriteDWORD((uint)method.Value); } } return(debugInfoBlob); }
// // returns the DEBUG_S_FUNC_MDTOKEN_MAP subsection as a byte array // DEBUG_S_FUNC_MDTOKEN_MAP subsection contains method RVA to mdToken mapping // // contents of subsection: // offset 0, 4 bytes: count of entries in the map // offset 4, 8*N bytes: 4 byte RVA + 4 byte 'offset' relative to the start of 'method data' // offset 4+8*N, * bytes: all method data packed sequentially with no padding. method data consists of // 1 byte 'count' of generic parameters, 3 bytes of method's rid and 'count' // variable sized ECMA formatted TypeSpec signatures for each generic parameter // // Compiler places the CTLToken (for a method) or the lexical funclet order (if a method has 1 or more funclets), // which binder uses to compute the RVA. // // all entries are sorted by 'offset' field. // // 'offset' optimization: if the method has no generic parameters, we don't need to pass in a signature // and can encode the mdToken of method in 'offset' // We do this by setting the high bit of 'offset' and then storing rid part of // token in last 3 bytes of 'offset' // internal DebugInfoBlob GetDebugMethodRVAToTokenMap(ManagedBinaryEmitter pseudoAssembly, IEnumerable <IMethodBodyNode> emittedMethods, out List <Relocation> debugRelocations) { DebugInfoBlob methodRVAToTokenMap = new DebugInfoBlob(); DebugInfoBlob methodDataBlob = new DebugInfoBlob(); debugRelocations = new List <Relocation>(); BlobBuilder blobBuilder = new BlobBuilder(); uint entryCount = 0; methodRVAToTokenMap.WriteDWORD(0); // Placeholder for count of entries in map. Will be udpated later. List <EmittedMethodWithILToken> tokenInOffsetEntries = new List <EmittedMethodWithILToken>(); foreach (IMethodBodyNode emitted in emittedMethods) { if (!(emitted.Method.GetTypicalMethodDefinition() is Internal.TypeSystem.Ecma.EcmaMethod)) { continue; } EntityHandle methodHandle = pseudoAssembly.EmitMetadataHandleForTypeSystemEntity(emitted.Method.GetTypicalMethodDefinition()); Debug.Assert(methodHandle.Kind == HandleKind.MemberReference); uint methodToken = (uint)MetadataTokens.GetToken(methodHandle); uint methodTokenRid = methodToken & 0xFFFFFF; if (!(emitted.Method.HasInstantiation || emitted.Method.OwningType.HasInstantiation)) { tokenInOffsetEntries.Add(new EmittedMethodWithILToken(emitted, methodTokenRid)); continue; } uint cGenericArguments = checked ((uint)emitted.Method.Instantiation.Length + (uint)emitted.Method.OwningType.Instantiation.Length); // Debugger format does not allow the debugging of methods that have more than 255 generic parameters (spread between the type and method instantiation) if (cGenericArguments > 0xFF) { continue; } blobBuilder.Clear(); // write the signature for each generic parameter of class foreach (TypeDesc instantiationType in emitted.Method.OwningType.Instantiation) { pseudoAssembly.EncodeSignatureForType(instantiationType, blobBuilder); } // write the signature for each generic parameter of the method foreach (TypeDesc instantiationType in emitted.Method.Instantiation) { pseudoAssembly.EncodeSignatureForType(instantiationType, blobBuilder); } Add_DEBUG_S_FUNC_MDTOKEN_MAP_Entry(methodRVAToTokenMap, debugRelocations, emitted, methodDataBlob.Size(), ref entryCount); methodDataBlob.WriteDWORD(cGenericArguments << 24 | methodTokenRid); methodDataBlob.WriteBuffer(blobBuilder); } // sort tokenInOffsetEntries based on tokenInOffset tokenInOffsetEntries.Sort(); foreach (EmittedMethodWithILToken emitted in tokenInOffsetEntries) { Add_DEBUG_S_FUNC_MDTOKEN_MAP_Entry(methodRVAToTokenMap, debugRelocations, emitted.EmittedMethod, emitted.IlTokenRid | 0x80000000, ref entryCount); } methodRVAToTokenMap.SetDWORDAtBlobIndex(0, entryCount); // // Update placeholder for count of entries in map methodRVAToTokenMap.WriteBuffer(methodDataBlob); return(methodRVAToTokenMap); }
// returns the DEBUG_S_TYPE_MDTOKEN_MAP subsection as a byte array // DEBUG_S_TYPE_MDTOKEN_MAP subsection contains type-index to mdToken mapping // // contents of subsection: // offset 0, 4 bytes: count of entries in the map // offset 4, 8*N bytes: 4 byte type-index + 4 byte 'offset' relative to the start of 'type data' // offset 4+8*N, * bytes: ECMA formatted type signature packed sequentially with no padding // // 'offset' optimization: for type signatures with size<= 4-bytes // we can store the signature in offset field such that // offset = (1 << 31) | (sig[0] << 24 | sig[1] << 16 | sig[2] << 8 | sig[3]) // We chose this bit encoding because sig[0] holds the CorElementType whose // highest bit is always 0 and the highest bit of offset can be used as a flag // to indicate that it is not an offset but the signature itself. // // all entries are sorted by 'offset' field and so offset-based entries are arranged before other // (raw-signature) entries (since raw-signature entries are of the form 0x80000000 | signature, and will always be // numerically bigger than the offset) // private DebugInfoBlob GetDebugTypeIndexToTokenMap(ManagedBinaryEmitter pseudoAssembly, ICollection <KeyValuePair <TypeDesc, uint> > completeKnownTypes) { DebugInfoBlob typeDataBlob = new DebugInfoBlob(); DebugInfoBlob typeIndexToTokenMapBlob = new DebugInfoBlob(); List <KeyValuePair <uint, uint> > sigInOffsetEntries = new List <KeyValuePair <uint, uint> >(); typeIndexToTokenMapBlob.WriteDWORD(checked ((uint)completeKnownTypes.Count)); BlobBuilder blobBuilder = new BlobBuilder(); foreach (var entry in completeKnownTypes) { uint typeIndex = entry.Value; blobBuilder.Clear(); pseudoAssembly.EncodeSignatureForType(entry.Key, blobBuilder); // if signature fits in 4-bytes, store it in sigInOffsetEntries // otherwise store it in the type-data blob if (blobBuilder.Count <= 4) { uint sigInOffset = 0x80000000; int i = 0; // This is a slightly confusing approach, but this is how one iterates through the bytes in a blobBuilder without flattening it to a byte[] foreach (Blob blob in blobBuilder.GetBlobs()) { foreach (byte b in blob.GetBytes()) { sigInOffset |= ((uint)b) << (8 * (3 - i)); i++; } } // sigInOffsetEntries will be later sorted and appended to typeIndexToTokenMapBlob sigInOffsetEntries.Add(new KeyValuePair <uint, uint>(typeIndex, sigInOffset)); } else { typeIndexToTokenMapBlob.WriteDWORD(typeIndex); typeIndexToTokenMapBlob.WriteDWORD(typeDataBlob.Size()); typeDataBlob.WriteBuffer(blobBuilder); } } // sort sigInOffsetEntries based on sigInOffset sigInOffsetEntries.Sort((KeyValuePair <uint, uint> left, KeyValuePair <uint, uint> right) => { if (left.Value < right.Value) { return(-1); } if (left.Value == right.Value) { return(0); } return(1); }); // write the sorted sigInOffsetEntries foreach (KeyValuePair <uint, uint> sigInOffsetEntry in sigInOffsetEntries) { typeIndexToTokenMapBlob.WriteDWORD(sigInOffsetEntry.Key); typeIndexToTokenMapBlob.WriteDWORD(sigInOffsetEntry.Value); } // add typeDataBlob to the end of m_typeIndexToTokenMapBlob typeIndexToTokenMapBlob.WriteBuffer(typeDataBlob.ToArray()); return(typeIndexToTokenMapBlob); }