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(); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } ObjectDataBuilder objDataBuilder = new ObjectDataBuilder(factory, relocsOnly); // Emit number of dictionaries in table objDataBuilder.AddSymbol(this); IReadOnlyCollection <GenericDictionaryNode> dictionariesEmitted = factory.MetadataManager.GetCompiledGenericDictionaries(); objDataBuilder.EmitInt(dictionariesEmitted.Count); DebugInfoBlob signatureData = new DebugInfoBlob(); BlobBuilder signatureBlobBuilder = new BlobBuilder(); BlobBuilder signatureLenBuilder = new BlobBuilder(); ManagedBinaryEmitter pseudoAssembly = factory.WindowsDebugData.DebugPseudoAssemblySection.PseudoAssembly; foreach (GenericDictionaryNode dictionary in dictionariesEmitted) { objDataBuilder.EmitReloc(dictionary, RelocType.IMAGE_REL_BASED_ADDR32NB); objDataBuilder.EmitUInt(signatureData.Size()); signatureBlobBuilder.Clear(); int typeDictLen = dictionary.TypeInstantiation.IsNull ? 0 : dictionary.TypeInstantiation.Length; int methodDictLen = dictionary.MethodInstantiation.IsNull ? 0 : dictionary.MethodInstantiation.Length; signatureBlobBuilder.WriteCompressedInteger(typeDictLen + methodDictLen); if (typeDictLen != 0) { foreach (TypeDesc type in dictionary.TypeInstantiation) { pseudoAssembly.EncodeSignatureForType(type, signatureBlobBuilder); } } if (methodDictLen != 0) { foreach (TypeDesc type in dictionary.MethodInstantiation) { pseudoAssembly.EncodeSignatureForType(type, signatureBlobBuilder); } } int blobSize = signatureBlobBuilder.Count; signatureLenBuilder.Clear(); signatureLenBuilder.WriteCompressedInteger(blobSize); // Prepend the signature data with a length signatureData.WriteBuffer(signatureLenBuilder); // And then attach the actual signature data signatureData.WriteBuffer(signatureBlobBuilder); } // Attach signature information to end after all of the rva/offset pairs objDataBuilder.EmitBytes(signatureData.ToArray()); return(objDataBuilder.ToObjectData()); }
// // 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); }