1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5//*****************************************************************************
6// File: module.cpp
7//
8
9//
10//*****************************************************************************
11#include "stdafx.h"
12#include "winbase.h"
13
14#include "metadataexports.h"
15
16#include "winbase.h"
17#include "corpriv.h"
18#include "corsym.h"
19#include "ildbsymlib.h"
20
21#include "pedecoder.h"
22
23//---------------------------------------------------------------------------------------
24// Update an existing metadata importer with a buffer
25//
26// Arguments:
27// pUnk - IUnknoown of importer to update.
28// pData - local buffer containing new metadata
29// cbData - size of buffer in bytes.
30// dwReOpenFlags - metadata flags to pass for reopening.
31//
32// Returns:
33// S_OK on success. Else failure.
34//
35// Notes:
36// This will call code:MDReOpenMetaDataWithMemoryEx from the metadata engine.
37STDAPI ReOpenMetaDataWithMemoryEx(
38 void *pUnk,
39 LPCVOID pData,
40 ULONG cbData,
41 DWORD dwReOpenFlags)
42{
43 HRESULT hr = MDReOpenMetaDataWithMemoryEx(pUnk,pData, cbData, dwReOpenFlags);
44 return hr;
45}
46
47//---------------------------------------------------------------------------------------
48// Initialize a new CordbModule around a Module in the target.
49//
50// Arguments:
51// pProcess - process that this module lives in
52// vmDomainFile - CLR cookie for module.
53CordbModule::CordbModule(
54 CordbProcess * pProcess,
55 VMPTR_Module vmModule,
56 VMPTR_DomainFile vmDomainFile)
57: CordbBase(pProcess, vmDomainFile.IsNull() ? VmPtrToCookie(vmModule) : VmPtrToCookie(vmDomainFile), enumCordbModule),
58 m_pAssembly(0),
59 m_pAppDomain(0),
60 m_classes(11),
61 m_functions(101),
62 m_vmDomainFile(vmDomainFile),
63 m_vmModule(vmModule),
64 m_EnCCount(0),
65 m_isIlWinMD(Uninitialized),
66 m_fForceMetaDataSerialize(FALSE),
67 m_nativeCodeTable(101)
68{
69 _ASSERTE(pProcess->GetProcessLock()->HasLock());
70
71 _ASSERTE(!vmModule.IsNull());
72
73 m_nLoadEventContinueCounter = 0;
74#ifdef _DEBUG
75 m_classes.DebugSetRSLock(pProcess->GetProcessLock());
76 m_functions.DebugSetRSLock(pProcess->GetProcessLock());
77#endif
78
79 // Fill out properties via DAC.
80 ModuleInfo modInfo;
81 pProcess->GetDAC()->GetModuleData(vmModule, &modInfo); // throws
82
83 m_PEBuffer.Init(modInfo.pPEBaseAddress, modInfo.nPESize);
84
85 m_fDynamic = modInfo.fIsDynamic;
86 m_fInMemory = modInfo.fInMemory;
87 m_vmPEFile = modInfo.vmPEFile;
88
89 if (!vmDomainFile.IsNull())
90 {
91 DomainFileInfo dfInfo;
92
93 pProcess->GetDAC()->GetDomainFileData(vmDomainFile, &dfInfo); // throws
94
95 m_pAppDomain = pProcess->LookupOrCreateAppDomain(dfInfo.vmAppDomain);
96 m_pAssembly = m_pAppDomain->LookupOrCreateAssembly(dfInfo.vmDomainAssembly);
97 }
98 else
99 {
100 // Not yet implemented
101 m_pAppDomain = pProcess->GetSharedAppDomain();
102 m_pAssembly = m_pAppDomain->LookupOrCreateAssembly(modInfo.vmAssembly);
103 }
104#ifdef _DEBUG
105 m_nativeCodeTable.DebugSetRSLock(GetProcess()->GetProcessLock());
106#endif
107
108 // MetaData is initialized lazily (via code:CordbModule::GetMetaDataImporter).
109 // Getting the metadata may be very expensive (especially if we go through the metadata locator, which
110 // invokes back to the data-target), so don't do it until asked.
111 // m_pIMImport, m_pInternalMetaDataImport are smart pointers that already initialize to NULL.
112}
113
114
115#ifdef _DEBUG
116//---------------------------------------------------------------------------------------
117// Callback helper for code:CordbModule::DbgAssertModuleDeleted
118//
119// Arguments
120// vmDomainFile - domain file in the enumeration
121// pUserData - pointer to the CordbModule that we just got an exit event for.
122//
123void DbgAssertModuleDeletedCallback(VMPTR_DomainFile vmDomainFile, void * pUserData)
124{
125 CordbModule * pThis = reinterpret_cast<CordbModule *>(pUserData);
126 INTERNAL_DAC_CALLBACK(pThis->GetProcess());
127
128 if (!pThis->m_vmDomainFile.IsNull())
129 {
130 VMPTR_DomainFile vmDomainFileDeleted = pThis->m_vmDomainFile;
131
132 CONSISTENCY_CHECK_MSGF((vmDomainFileDeleted != vmDomainFile),
133 ("A Module Unload event was sent for a module, but it still shows up in the enumeration.\n vmDomainFileDeleted=%p\n",
134 VmPtrToCookie(vmDomainFileDeleted)));
135 }
136}
137
138//---------------------------------------------------------------------------------------
139// Assert that a module is no longer discoverable via enumeration.
140//
141// Notes:
142// See code:IDacDbiInterface#Enumeration for rules that we're asserting.
143// This is a debug only method. It's conceptually similar to
144// code:CordbProcess::DbgAssertAppDomainDeleted.
145//
146void CordbModule::DbgAssertModuleDeleted()
147{
148 GetProcess()->GetDAC()->EnumerateModulesInAssembly(
149 m_pAssembly->GetDomainAssemblyPtr(),
150 DbgAssertModuleDeletedCallback,
151 this);
152}
153#endif // _DEBUG
154
155CordbModule::~CordbModule()
156{
157 // We should have been explicitly neutered before our internal ref went to 0.
158 _ASSERTE(IsNeutered());
159
160 _ASSERTE(m_pIMImport == NULL);
161}
162
163// Neutered by CordbAppDomain
164void CordbModule::Neuter()
165{
166 // m_pAppDomain, m_pAssembly assigned w/o AddRef()
167 m_classes.NeuterAndClear(GetProcess()->GetProcessLock());
168 m_functions.NeuterAndClear(GetProcess()->GetProcessLock());
169
170 m_nativeCodeTable.NeuterAndClear(GetProcess()->GetProcessLock());
171 m_pClass.Clear();
172
173 // This is very important because it also releases the metadata's potential file locks.
174 m_pInternalMetaDataImport.Clear();
175 m_pIMImport.Clear();
176
177 CordbBase::Neuter();
178}
179
180//
181// Creates an IStream based off the memory described by the TargetBuffer.
182//
183// Arguments:
184// pProcess - process that buffer is valid in.
185// buffer - memory range in target
186// ppStream - out parameter to receive the new stream. *ppStream == NULL on input.
187// caller owns the new object and must call Release.
188//
189// Returns:
190// Throws on error.
191// Common errors include if memory is missing in the target.
192//
193// Notes:
194// This will copy the memory over from the TargetBuffer, and then create a new IStream
195// object around it.
196//
197void GetStreamFromTargetBuffer(CordbProcess * pProcess, TargetBuffer buffer, IStream ** ppStream)
198{
199 CONTRACTL
200 {
201 THROWS;
202 }
203 CONTRACTL_END;
204
205 _ASSERTE(ppStream != NULL);
206 _ASSERTE(*ppStream == NULL);
207
208 int cbSize = buffer.cbSize;
209 NewArrayHolder<BYTE> localBuffer(new BYTE[cbSize]);
210
211 pProcess->SafeReadBuffer(buffer, localBuffer);
212
213 HRESULT hr = E_FAIL;
214 hr = CInMemoryStream::CreateStreamOnMemoryCopy(localBuffer, cbSize, ppStream);
215 IfFailThrow(hr);
216 _ASSERTE(*ppStream != NULL);
217}
218
219//
220// Helper API to get in-memory symbols from the target into a host stream object.
221//
222// Arguments:
223// ppStream - out parameter to receive the new stream. *ppStream == NULL on input.
224// caller owns the new object and must call Release.
225//
226// Returns:
227// kSymbolFormatNone if no PDB stream is present. This is a common case for
228// file-based modules, and also for dynamic modules that just aren't tracking
229// debug information.
230// The format of the symbols stored into ppStream. This is common:
231// - Ref.Emit modules if the debuggee generated debug symbols,
232// - in-memory modules (such as Load(Byte[], Byte[])
233// - hosted modules.
234// Throws on error
235//
236IDacDbiInterface::SymbolFormat CordbModule::GetInMemorySymbolStream(IStream ** ppStream)
237{
238 // @dbgtodo : add a PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM contract
239 // This function is mainly called internally in dbi, and also by the shim to emulate the
240 // UpdateModuleSymbols callback on attach.
241
242 CONTRACTL
243 {
244 THROWS;
245 }
246 CONTRACTL_END;
247
248 _ASSERTE(ppStream != NULL);
249 _ASSERTE(*ppStream == NULL);
250 *ppStream = NULL;
251
252 TargetBuffer bufferPdb;
253 IDacDbiInterface::SymbolFormat symFormat;
254 GetProcess()->GetDAC()->GetSymbolsBuffer(m_vmModule, &bufferPdb, &symFormat);
255 if (bufferPdb.IsEmpty())
256 {
257 // No in-memory PDB. Common case.
258 _ASSERTE(symFormat == IDacDbiInterface::kSymbolFormatNone);
259 return IDacDbiInterface::kSymbolFormatNone;
260 }
261 else
262 {
263 _ASSERTE(symFormat != IDacDbiInterface::kSymbolFormatNone);
264 GetStreamFromTargetBuffer(GetProcess(), bufferPdb, ppStream);
265 return symFormat;
266 }
267}
268
269//---------------------------------------------------------------------------------------
270// Accessor for PE file.
271//
272// Returns:
273// VMPTR_PEFile for this module. Should always be non-null
274//
275// Notes:
276// A main usage of this is to find the proper internal MetaData importer.
277// DACized code needs to map from PEFile --> IMDInternalImport.
278//
279VMPTR_PEFile CordbModule::GetPEFile()
280{
281 return m_vmPEFile;
282}
283
284//---------------------------------------------------------------------------------------
285//
286// Top-level getter for the public metadata importer for this module
287//
288// Returns:
289// metadata importer.
290// Never returns NULL. Will throw some hr (likely CORDBG_E_MISSING_METADATA) instead.
291//
292// Notes:
293// This will lazily create the metadata, possibly invoking back into the data-target.
294IMetaDataImport * CordbModule::GetMetaDataImporter()
295{
296 CONTRACTL
297 {
298 THROWS;
299 }
300 CONTRACTL_END;
301
302
303 // If we already have it, then we're done.
304 // This is critical to do at the top of this function to avoid potential recursion.
305 if (m_pIMImport != NULL)
306 {
307 return m_pIMImport;
308 }
309
310 // Lazily initialize
311
312
313 // Fetch metadata from target
314 LOG((LF_CORDB,LL_INFO1000, "CM::GMI Lazy init refreshing metadata\n"));
315
316 ALLOW_DATATARGET_MISSING_MEMORY(
317 RefreshMetaData();
318 );
319
320 // If lookup failed from the Module & target memory, try the metadata locator interface
321 // from debugger, if we have one.
322 if (m_pIMImport == NULL)
323 {
324 bool isILMetaDataForNGENImage; // Not currently used for anything.
325
326 // The process's LookupMetaData will ping the debugger's ICorDebugMetaDataLocator iface.
327 CordbProcess * pProcess = GetProcess();
328 RSLockHolder processLockHolder(pProcess->GetProcessLock());
329 m_pInternalMetaDataImport.Clear();
330
331 // Do not call code:CordbProcess::LookupMetaData from this function. It will try to load
332 // through the CordbModule again which will end up back here, and on failure you'll fill the stack.
333 // Since we've already done everything possible from the Module anyhow, just call the
334 // stuff that talks to the debugger.
335 // Don't do anything with the ptr returned here, since it's really m_pInternalMetaDataImport.
336 pProcess->LookupMetaDataFromDebugger(m_vmPEFile, isILMetaDataForNGENImage, this);
337 }
338
339 // If we still can't get it, throw.
340 if (m_pIMImport == NULL)
341 {
342 ThrowHR(CORDBG_E_MISSING_METADATA);
343 }
344
345 return m_pIMImport;
346}
347
348// Refresh the metadata cache if a profiler added new rows.
349//
350// Arguments:
351// token - token that we want to ensure is in the metadata cache.
352//
353// Notes:
354// In profiler case, this may be referred to new rows and we may need to update the metadata
355// This only supports StandAloneSigs.
356//
357void CordbModule::UpdateMetaDataCacheIfNeeded(mdToken token)
358{
359 CONTRACTL
360 {
361 THROWS;
362 }
363 CONTRACTL_END;
364
365 LOG((LF_CORDB,LL_INFO10000, "CM::UMCIN token=0x%x\n", token));
366
367 // If we aren't trying to keep parity with our legacy profiler metadata update behavior
368 // then we should avoid this temporary update mechanism entirely
369 if(GetProcess()->GetWriteableMetadataUpdateMode() != LegacyCompatPolicy)
370 {
371 return;
372 }
373
374 // the metadata in WinMD is currently static since there's no
375 // support for profilers or EnC so we can simply exit early.
376 if (IsWinMD())
377 {
378 LOG((LF_CORDB,LL_INFO10000, "CM::UMCIN token is in WinMD, exiting\n"));
379 return;
380 }
381
382 //
383 // 1) Check if in-range? Compare against tables, etc.
384 //
385 if(CheckIfTokenInMetaData(token))
386 {
387 LOG((LF_CORDB,LL_INFO10000, "CM::UMCIN token was present\n"));
388 return;
389 }
390
391 //
392 // 2) Copy over new MetaData. From now on we assume that the profiler is
393 // modifying module metadata and that we need to serialize in process
394 // at each refresh
395 //
396 LOG((LF_CORDB,LL_INFO10000, "CM::UMCIN token was not present, refreshing\n"));
397 m_fForceMetaDataSerialize = TRUE;
398 RefreshMetaData();
399
400 // If we are dump debugging, we may still not have it. Nothing to be done.
401}
402
403// Returns TRUE if the token is present, FALSE if not.
404BOOL CordbModule::CheckIfTokenInMetaData(mdToken token)
405{
406 CONTRACTL
407 {
408 THROWS;
409 }
410 CONTRACTL_END;
411 LOG((LF_CORDB,LL_INFO10000, "CM::CITIM token=0x%x\n", token));
412 _ASSERTE(TypeFromToken(token) == mdtSignature);
413 // we shouldn't be doing this on WinMD modules since they don't implement IID_IMetaDataTables
414 _ASSERTE(!IsWinMD());
415 RSExtSmartPtr<IMetaDataTables> pTable;
416
417 HRESULT hr = GetMetaDataImporter()->QueryInterface(IID_IMetaDataTables, (void**) &pTable);
418
419 _ASSERTE(SUCCEEDED(hr));
420 if (FAILED(hr))
421 {
422 ThrowHR(hr);
423 }
424
425 ULONG cbRowsAvailable; // number of rows in the table
426
427 hr = pTable->GetTableInfo(
428 mdtSignature >> 24, // [IN] Which table.
429 NULL, // [OUT] Size of a row, bytes.
430 &cbRowsAvailable, // [OUT] Number of rows.
431 NULL, // [OUT] Number of columns in each row.
432 NULL, // [OUT] Key column, or -1 if none.
433 NULL); // [OUT] Name of the table.
434
435 _ASSERTE(SUCCEEDED(hr));
436 if (FAILED(hr))
437 {
438 ThrowHR(hr);
439 }
440
441
442 // Rows start counting with number 1.
443 ULONG rowRequested = RidFromToken(token);
444 LOG((LF_CORDB,LL_INFO10000, "CM::UMCIN requested=0x%x available=0x%x\n", rowRequested, cbRowsAvailable));
445 return (rowRequested <= cbRowsAvailable);
446}
447
448// This helper class ensures the remote serailzied buffer gets deleted in the RefreshMetaData
449// function below
450class CleanupRemoteBuffer
451{
452public:
453 CordbProcess* pProcess;
454 CordbModule* pModule;
455 TargetBuffer bufferMetaData;
456 BOOL fDoCleanup;
457
458 CleanupRemoteBuffer() :
459 fDoCleanup(FALSE) { }
460
461 ~CleanupRemoteBuffer()
462 {
463 if(fDoCleanup)
464 {
465 //
466 // Send 2nd event to free buffer.
467 //
468 DebuggerIPCEvent event;
469 pProcess->InitIPCEvent(&event,
470 DB_IPCE_RESOLVE_UPDATE_METADATA_2,
471 true,
472 pModule->GetAppDomain()->GetADToken());
473
474 event.MetadataUpdateRequest.pMetadataStart = CORDB_ADDRESS_TO_PTR(bufferMetaData.pAddress);
475
476 // Note: two-way event here...
477 IfFailThrow(pProcess->SendIPCEvent(&event, sizeof(DebuggerIPCEvent)));
478 _ASSERTE(event.type == DB_IPCE_RESOLVE_UPDATE_METADATA_2_RESULT);
479 }
480 }
481
482};
483
484// Called to refetch metadata. This occurs when a dynamic module grows or the profiler
485// has edited the metadata
486void CordbModule::RefreshMetaData()
487{
488 CONTRACTL
489 {
490 THROWS;
491 }
492 CONTRACTL_END;
493
494 LOG((LF_CORDB,LL_INFO1000, "CM::RM\n"));
495
496 // There are several different ways we can get the metadata
497 // 1) [Most common] Module is loaded into VM and never changed. The importer
498 // will be constructed refering to the file on disk. This is a significant
499 // working set win because the VM and debugger share the image. If there is
500 // an error reading by file we can fall back to case #2 for these modules
501 // 2) Most modules have a buffer in target memory that represents their
502 // metadata. We copy that data over the RS and construct an in-memory
503 // importer on top of it.
504 // 3) The only modules that don't have a suitable buffer (case #2) are those
505 // modified in memory via the profiling API (or ENC). A message can be sent from
506 // the debugger to the debuggee instructing it to allocate a buffer and
507 // serialize the metadata into it. Then we copy that data to the RS and
508 // construct an in-memory importer on top of it.
509 // We don't need to send this message in the ENC case because the debugger
510 // has the same changes applied as the debuggee.
511 // 4) Case #3 won't work when dump debugging because we can't send IPC events.
512 // Instead we can locate chunks of the metadata pointed to in the implementation
513 // details of a remote MDInternalRW object, marshal that memory over to the
514 // debugger process, and then put a metadata reader on top of it.
515 // In time this DAC'ized metadata could be used in almost any scenario,
516 // although its probably worth keeping the file mapping technique in case
517 // #1 around for its performance wins.
518
519 CordbProcess * pProcess = GetProcess();
520 TargetBuffer bufferMetaData;
521 CleanupRemoteBuffer cleanup; // this local has a destructor to do some finally work
522
523
524 // check for scenarios we might want to handle with case #4
525 if (GetProcess()->GetShim() == NULL &&
526 GetProcess()->GetWriteableMetadataUpdateMode() == AlwaysShowUpdates &&
527 !m_fDynamic)
528 {
529 //None of the above requirements are particularly hard to change in the future as needed...
530 // a) dump-debugging mode - If we do this on a process that can move forward we need a mechanism to determine
531 // when to refetch the metadata.
532 // b) AlwaysShowUpdates - this is purely a risk mitigation choice, there aren't any known back-compat issues
533 // using DAC'ized metadata. If you want back-compat with the in-proc debugging behavior
534 // you need to figure out how to ReOpen the same public MD interface with new data.
535 // c) !m_fDynamic - A risk mitigation choice. Initial testing suggests it would work fine.
536
537
538 // So far we've only got a reader for in-memory-writable metadata (MDInternalRW implementation)
539 // We could make a reader for MDInternalRO, but no need yet. This also ensures we don't encroach into common
540 // scenario where we can map a file on disk.
541 TADDR remoteMDInternalRWAddr = NULL;
542 GetProcess()->GetDAC()->GetPEFileMDInternalRW(m_vmPEFile, &remoteMDInternalRWAddr);
543 if (remoteMDInternalRWAddr != NULL)
544 {
545 // we should only be doing this once to initialize, we don't support reopen with this technique
546 _ASSERTE(m_pIMImport == NULL);
547 ULONG32 mdStructuresVersion;
548 HRESULT hr = GetProcess()->GetDAC()->GetMDStructuresVersion(&mdStructuresVersion);
549 IfFailThrow(hr);
550 ULONG32 mdStructuresDefines;
551 hr = GetProcess()->GetDAC()->GetDefinesBitField(&mdStructuresDefines);
552 IfFailThrow(hr);
553 IMetaDataDispenserCustom* pDispCustom = NULL;
554 hr = GetProcess()->GetDispenser()->QueryInterface(IID_IMetaDataDispenserCustom, (void**)&pDispCustom);
555 IfFailThrow(hr);
556 IMDCustomDataSource* pDataSource = NULL;
557 hr = CreateRemoteMDInternalRWSource(remoteMDInternalRWAddr, GetProcess()->GetDataTarget(), mdStructuresDefines, mdStructuresVersion, &pDataSource);
558 IfFailThrow(hr);
559 IMetaDataImport* pImport = NULL;
560 hr = pDispCustom->OpenScopeOnCustomDataSource(pDataSource, 0, IID_IMetaDataImport, (IUnknown**)&m_pIMImport);
561 IfFailThrow(hr);
562 UpdateInternalMetaData();
563 return;
564 }
565 }
566
567 if(!m_fForceMetaDataSerialize) // case 1 and 2
568 {
569 LOG((LF_CORDB,LL_INFO10000, "CM::RM !m_fForceMetaDataSerialize case\n"));
570 GetProcess()->GetDAC()->GetMetadata(m_vmModule, &bufferMetaData); // throws
571 }
572 else if (GetProcess()->GetShim() == NULL) // case 3 won't work on a dump so don't try
573 {
574 return;
575 }
576 else // case 3 on a live process
577 {
578 LOG((LF_CORDB,LL_INFO10000, "CM::RM m_fForceMetaDataSerialize case\n"));
579 //
580 // Send 1 event to get metadata. This allocates a buffer
581 //
582 DebuggerIPCEvent event;
583 pProcess->InitIPCEvent(&event,
584 DB_IPCE_RESOLVE_UPDATE_METADATA_1,
585 true,
586 GetAppDomain()->GetADToken());
587
588 event.MetadataUpdateRequest.vmModule = m_vmModule;
589
590 // Note: two-way event here...
591 IfFailThrow(pProcess->SendIPCEvent(&event, sizeof(DebuggerIPCEvent)));
592
593 _ASSERTE(event.type == DB_IPCE_RESOLVE_UPDATE_METADATA_1_RESULT);
594
595 //
596 // Update it on the RS
597 //
598 bufferMetaData.Init(PTR_TO_CORDB_ADDRESS(event.MetadataUpdateRequest.pMetadataStart), (ULONG) event.MetadataUpdateRequest.nMetadataSize);
599
600 // init the cleanup object to ensure the buffer gets destroyed later
601 cleanup.bufferMetaData = bufferMetaData;
602 cleanup.pProcess = pProcess;
603 cleanup.pModule = this;
604 cleanup.fDoCleanup = TRUE;
605 }
606
607 InitMetaData(bufferMetaData, IsFileMetaDataValid()); // throws
608}
609
610// Determines whether the on-disk metadata for this module is usable as the
611// current metadata
612BOOL CordbModule::IsFileMetaDataValid()
613{
614 bool fOpenFromFile = true;
615
616 // Dynamic, In-memory, modules must be OpenScopeOnMemory.
617 // For modules that require the metadata to be serialized in memory, we must also OpenScopeOnMemory
618 // For Enc, we'll can use OpenScope(onFile) and it will get converted to Memory when we get an emitter.
619 // We're called from before the ModuleLoad callback, so EnC status hasn't been set yet, so
620 // EnC will be false.
621 if (m_fDynamic || m_fInMemory || m_fForceMetaDataSerialize)
622 {
623 LOG((LF_CORDB,LL_INFO10000, "CM::IFMV: m_fDynamic=0x%x m_fInMemory=0x%x m_fForceMetaDataSerialize=0x%x\n",
624 m_fDynamic, m_fInMemory, m_fForceMetaDataSerialize));
625 fOpenFromFile = false;
626 }
627
628#ifdef _DEBUG
629 // Reg key override to force us to use Open-by-memory. This can let us run perf tests to
630 // compare the Open-by-mem vs. Open-by-file.
631 static DWORD openFromFile = 99;
632 if (openFromFile == 99)
633 openFromFile = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgNoOpenMDByFile);
634
635 if (openFromFile)
636 {
637 LOG((LF_CORDB,LL_INFO10000, "CM::IFMV: INTERNAL_DbgNoOpenMDByFile is set\n"));
638 fOpenFromFile = false;
639 }
640#endif
641
642 LOG((LF_CORDB,LL_INFO10000, "CM::IFMV: returns 0x%x\n", fOpenFromFile));
643 return fOpenFromFile;
644}
645
646//---------------------------------------------------------------------------------------
647// Accessor for Internal MetaData importer. This is lazily initialized.
648//
649// Returns:
650// Internal MetaDataImporter, which can be handed off to DAC. Not AddRef().
651// Should be non-null. Throws on error.
652//
653// Notes:
654// An internal metadata importer is used extensively by DAC-ized code (And Edit-and-continue).
655// This should not be handed out through ICorDebug.
656IMDInternalImport * CordbModule::GetInternalMD()
657{
658 if (m_pInternalMetaDataImport == NULL)
659 {
660 UpdateInternalMetaData(); // throws
661 }
662 return m_pInternalMetaDataImport;
663}
664
665//---------------------------------------------------------------------------------------
666// The one-stop top-level initialization function the metadata (both public and private) for this module.
667//
668// Arguments:
669// buffer - valid buffer into target containing the metadata.
670// useFileMappingOptimization - if true this allows us to attempt just opening the importer
671// by using the metadata in the module on disk. if false or
672// if the attempt fails we open the metadata import on memory in
673// target buffer
674//
675// Notes:
676// This will initialize both the internal and public metadata from the buffer in the target.
677// Only called as a helper from RefreshMetaData()
678//
679// This may throw (eg, target buffer is missing).
680//
681void CordbModule::InitMetaData(TargetBuffer buffer, BOOL allowFileMappingOptimization)
682{
683 CONTRACTL
684 {
685 THROWS;
686 }
687 CONTRACTL_END;
688
689 LOG((LF_CORDB,LL_INFO100000, "CM::IM: initing with remote buffer 0x%p length 0x%x\n",
690 CORDB_ADDRESS_TO_PTR(buffer.pAddress), buffer.cbSize));
691
692 // clear all the metadata
693 m_pInternalMetaDataImport.Clear();
694
695 if (m_pIMImport == NULL)
696 {
697 // The optimization we're going for here is that the OS will use the same physical memory to
698 // back multiple ReadOnly opens of the same file. Thus since we expect the target process in
699 // live debugging, or the debugger in dump debugging, has already opened the file we would
700 // like to not create a local buffer and spend time copying in metadata from the target when
701 // the OS will happily do address lookup magic against the same physical memory for everyone.
702
703
704 // Try getting the data from the file if allowed, and fall back to using the buffer
705 // if required
706 HRESULT hr = S_OK;
707 if (allowFileMappingOptimization)
708 {
709 hr = InitPublicMetaDataFromFile();
710 if(FAILED(hr))
711 {
712 LOG((LF_CORDB,LL_INFO1000000, "CM::IPM: File mapping failed with hr=0x%x\n", hr));
713 }
714 }
715
716 if(!allowFileMappingOptimization || FAILED(hr))
717 {
718 // This is where the expensive copy of all metadata content from target memory
719 // that we would like to try and avoid happens.
720 InitPublicMetaData(buffer);
721 }
722 }
723 else
724 {
725 // We've already handed out an Import object, and so we can't create a new pointer instance.
726 // Instead, we update the existing instance with new data.
727 UpdatePublicMetaDataFromRemote(buffer);
728 }
729
730 // if we haven't set it by this point UpdateInternalMetaData below is going to get us
731 // in an infinite loop of refreshing public metadata
732 _ASSERTE(m_pIMImport != NULL);
733
734 // Now that public metadata has changed, force internal metadata to update too.
735 // Public and internal metadata expose different access interfaces to the same underlying storage.
736 UpdateInternalMetaData();
737}
738
739//---------------------------------------------------------------------------------------
740// Updates the Internal MetaData object from the public importer. Lazily fetch public importer if needed.
741//
742// Assumptions:
743// Caller has cleared Internal metadata before even updating public metadata.
744// This way, if the caller fails halfway through updating the public metadata, we don't have
745// stale internal MetaData.
746void CordbModule::UpdateInternalMetaData()
747{
748 CONTRACTL
749 {
750 THROWS;
751 }
752 CONTRACTL_END;
753
754 // Caller should have already cleared it.
755 _ASSERTE(m_pInternalMetaDataImport == NULL);
756
757 // Get the importer. If it's currently null, this will go fetch it.
758 IMetaDataImport * pImport = GetMetaDataImporter(); // throws
759
760 // If both the public and the private interfaces are NULL on entry to this function, the call above will
761 // recursively call this function. This can happen if the caller calls GetInternalMD() directly
762 // instead of InitMetaData(). In this case, the above function call will have initialized the internal
763 // interface as well, so we need to check for it here.
764
765 if (m_pInternalMetaDataImport == NULL)
766 {
767 HRESULT hr = GetMDInternalInterfaceFromPublic(
768 pImport,
769 IID_IMDInternalImport,
770 reinterpret_cast<void**> (&m_pInternalMetaDataImport));
771
772 if (m_pInternalMetaDataImport == NULL)
773 {
774 ThrowHR(hr);
775 }
776 }
777
778 _ASSERTE(m_pInternalMetaDataImport != NULL);
779}
780
781// Initialize the public metadata.
782//
783// The debuggee already has a copy of the metadata in its process.
784// If we OpenScope on file as read-only, the OS file-system will share our metadata with the
785// copy in the debuggee. This can be a major perf win. FX metadata can be over 8 MB+.
786// OpenScopeOnMemory can't be shared b/c we allocate a buffer.
787HRESULT CordbModule::InitPublicMetaDataFromFile()
788{
789 INTERNAL_API_ENTRY(this->GetProcess());
790
791 // @dbgtodo metadata - In v3, we can't assume we have the same path namespace as the target (i.e. it could be
792 // a dump or remote), so we can't just try and open the file. Instead we have to rely on interfaces
793 // on the datatarget to map the metadata here. Note that this must also work for minidumps where the
794 // metadata isn't necessarily in the dump image.
795
796 // Get filename. There are 2 filenames to choose from:
797 // - ngen (if applicable).
798 // - non-ngen (aka "normal").
799 // By loading metadata out of the same OS file as loaded into the debuggee space, the OS can share those pages.
800 const WCHAR * szFullPathName = NULL;
801 bool fDebuggerLoadingNgen = false;
802 bool fDebuggeeLoadedNgen = false;
803 szFullPathName = GetNGenImagePath();
804
805 if(szFullPathName != NULL)
806 {
807 fDebuggeeLoadedNgen = true;
808 fDebuggerLoadingNgen = true;
809
810#ifndef FEATURE_PAL
811 // NGEN images are large and we shouldn't load them if they won't be shared, therefore fail the NGEN mapping and
812 // fallback to IL image if the debugger doesn't have the image loaded already.
813 // Its possible that the debugger would still load the NGEN image sometime in the future and we will miss a sharing
814 // opportunity. Its an acceptable loss from an imperfect heuristic.
815 if (NULL == WszGetModuleHandle(szFullPathName))
816#endif
817 {
818 szFullPathName = NULL;
819 fDebuggerLoadingNgen = false;
820 }
821
822 }
823
824 // If we don't have or decided not to load the NGEN image, check to see if IL image is available
825 if (!fDebuggerLoadingNgen)
826 {
827 szFullPathName = GetModulePath();
828 }
829
830 // If we are doing live debugging we shouldn't use metadata from an IL image because it doesn't match closely enough.
831 // In particular the RVAs for IL code headers are different between the two images which will cause all IL code and
832 // local var signature lookups to fail. With further work we could compensate for the RVAs by computing
833 // the image layout differences and adjusting the returned RVAs, but there may be other differences that need to be accounted
834 // for as well. If we did go that route we should do a binary diff across a variety of NGEN/IL image metadata blobs to
835 // get a concrete understanding of the format differences.
836 //
837 // This check should really be 'Are we OK with only getting the functionality level of mini-dump debugging?' but since we
838 // don't know the debugger's intent we guess whether or not we are doing dump debugging by checking if we are shimmed. Once
839 // the shim supports live debugging we should probably just stop automatically falling back to IL image and let the debugger
840 // decide via the ICorDebugMetadataLocator interface.
841 if(fDebuggeeLoadedNgen && !fDebuggerLoadingNgen && GetProcess()->GetShim()!=NULL)
842 {
843 // The IL image might be there, but we shouldn't use it for live debugging
844 return CORDBG_E_MISSING_METADATA;
845 }
846
847
848 // @dbgtodo metadata - This is really a CreateFile() call which we can't do. We must offload this to
849 // the data target for the dump-debugging scenarios.
850 //
851 // We're opening it as "read". If we QI for an IEmit interface (which we need for EnC),
852 // then the metadata engine will convert it to a "write" underneath us.
853 // We want "read" so that we can let the OS share the pages.
854 DWORD dwOpenFlags = 0;
855
856 // If we know we're never going to need to write (i.e. never do EnC), then we should indicate
857 // that to metadata by telling it this interface will always be read-only. By passing read-only,
858 // the metadata library will then also share the VM space for the image when the same image is
859 // opened multiple times for multiple AppDomains.
860 // We don't currently have a way to tell absolutely whether this module will support EnC, but we
861 // know that NGen modules NEVER support EnC, and NGen is the common case that eats up a lot of VM.
862 // So we'll use the heuristic of opening the metadata for all ngen images as read-only. Ideally
863 // we'd go even further here (perhaps even changing metadata to map only the region of the file it
864 // needs).
865 if (fDebuggerLoadingNgen)
866 {
867 dwOpenFlags = ofReadOnly | ofTrustedImage;
868 }
869
870 // This is the only place we ever validate that the file matches, because we're potentially
871 // loading the file from disk ourselves. We're doing this without giving the debugger a chance
872 // to do anything. We should never load a file that isn't an exact match.
873 return InitPublicMetaDataFromFile(szFullPathName, dwOpenFlags, true);
874}
875
876// We should only ever validate we have the correct file if it's a file we found ourselves.
877// We allow the debugger to choose their own policy with regard to using metadata from the IL image
878// when debugging an NI, or even intentionally using mismatched metadata if they like.
879HRESULT CordbModule::InitPublicMetaDataFromFile(const WCHAR * pszFullPathName,
880 DWORD dwOpenFlags,
881 bool validateFileInfo)
882{
883#ifdef FEATURE_PAL
884 // UNIXTODO: Some intricate details of file mapping don't work on Linux as on Windows.
885 // We have to revisit this and try to fix it for POSIX system.
886 return E_FAIL;
887#else
888 if (validateFileInfo)
889 {
890 // Check that we've got the right file to target.
891 // There's nothing to prevent some other file being copied in for live, and with
892 // dump debugging there's nothing to say that we're not on another machine where a different
893 // file is at the same path.
894 // If we can't validate we have a hold of the correct file, we should not open it.
895 // We will fall back on asking the debugger to get us the correct file, or copying
896 // target memory back to the debugger.
897 DWORD dwImageTimeStamp = 0;
898 DWORD dwImageSize = 0;
899 bool isNGEN = false; // unused
900 StringCopyHolder filePath;
901
902
903 _ASSERTE(!m_vmPEFile.IsNull());
904 // MetaData lookup favors the NGEN image, which is what we want here.
905 if (!this->GetProcess()->GetDAC()->GetMetaDataFileInfoFromPEFile(m_vmPEFile,
906 dwImageTimeStamp,
907 dwImageSize,
908 isNGEN,
909 &filePath))
910 {
911 LOG((LF_CORDB,LL_WARNING, "CM::IM: Couldn't get metadata info for file \"%s\"\n", pszFullPathName));
912 return CORDBG_E_MISSING_METADATA;
913 }
914
915 // If the timestamp and size don't match, then this is the wrong file!
916 // Map the file and check them.
917 HandleHolder hMDFile = WszCreateFile(pszFullPathName,
918 GENERIC_READ,
919 FILE_SHARE_READ,
920 NULL, // default security descriptor
921 OPEN_EXISTING,
922 FILE_ATTRIBUTE_NORMAL,
923 NULL);
924
925 if (hMDFile == INVALID_HANDLE_VALUE)
926 {
927 LOG((LF_CORDB,LL_WARNING, "CM::IM: Couldn't open file \"%s\" (GLE=%x)\n", pszFullPathName, GetLastError()));
928 return CORDBG_E_MISSING_METADATA;
929 }
930
931 DWORD dwFileHigh = 0;
932 DWORD dwFileLow = GetFileSize(hMDFile, &dwFileHigh);
933 if (dwFileLow == INVALID_FILE_SIZE)
934 {
935 LOG((LF_CORDB,LL_WARNING, "CM::IM: File \"%s\" had invalid size.\n", pszFullPathName));
936 return CORDBG_E_MISSING_METADATA;
937 }
938
939 _ASSERTE(dwFileHigh == 0);
940
941 HandleHolder hMap = WszCreateFileMapping(hMDFile, NULL, PAGE_READONLY, dwFileHigh, dwFileLow, NULL);
942 if (hMap == NULL)
943 {
944 LOG((LF_CORDB,LL_WARNING, "CM::IM: Couldn't create mapping of file \"%s\" (GLE=%x)\n", pszFullPathName, GetLastError()));
945 return CORDBG_E_MISSING_METADATA;
946 }
947
948 MapViewHolder hMapView = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
949 if (hMapView == NULL)
950 {
951 LOG((LF_CORDB,LL_WARNING, "CM::IM: Couldn't map view of file \"%s\" (GLE=%x)\n", pszFullPathName, GetLastError()));
952 return CORDBG_E_MISSING_METADATA;
953 }
954
955 // Mapped as flat file, have PEDecoder go find what we want.
956 PEDecoder pedecoder(hMapView, (COUNT_T)dwFileLow);
957
958 if (!pedecoder.HasNTHeaders())
959 {
960 LOG((LF_CORDB,LL_WARNING, "CM::IM: \"%s\" did not have PE headers!\n", pszFullPathName));
961 return CORDBG_E_MISSING_METADATA;
962 }
963
964 if ((dwImageSize != pedecoder.GetVirtualSize()) ||
965 (dwImageTimeStamp != pedecoder.GetTimeDateStamp()))
966 {
967 LOG((LF_CORDB,LL_WARNING, "CM::IM: Validation of \"%s\" failed. "
968 "Expected size=%x, Expected timestamp=%x, Actual size=%x, Actual timestamp=%x\n",
969 pszFullPathName,
970 pedecoder.GetVirtualSize(),
971 pedecoder.GetTimeDateStamp(),
972 dwImageSize,
973 dwImageTimeStamp));
974 return CORDBG_E_MISSING_METADATA;
975 }
976
977 // All checks passed, go ahead and load this file for real.
978 }
979
980 // Get metadata Dispenser.
981 IMetaDataDispenserEx * pDisp = GetProcess()->GetDispenser();
982
983 HRESULT hr = pDisp->OpenScope(pszFullPathName, dwOpenFlags, IID_IMetaDataImport, (IUnknown**)&m_pIMImport);
984 _ASSERTE(SUCCEEDED(hr) == (m_pIMImport != NULL));
985
986 if (FAILED(hr))
987 {
988 // This should never happen in normal scenarios. It could happen if someone has renamed
989 // the assembly after it was opened by the debugee process, but this should be rare enough
990 // that we don't mind taking the perf. hit and loading from memory.
991 // @dbgtodo metadata - would this happen in the shadow-copy scenario?
992 LOG((LF_CORDB,LL_WARNING, "CM::IM: Couldn't open metadata in file \"%s\" (hr=%x)\n", pszFullPathName, hr));
993 }
994
995 return hr;
996#endif // FEATURE_PAL
997}
998
999//---------------------------------------------------------------------------------------
1000// Initialize the public metadata.
1001//
1002// Arguments:
1003// buffer - valid buffer into target containing the metadata.
1004//
1005// Assumptions:
1006// This is an internal function which should only be called once to initialize the
1007// metadata. Future attempts to re-initialize (in dynamic cases) should call code:CordbModule::UpdatePublicMetaDataFromRemote
1008// After the public metadata is initialized, initialize private metadata via code:CordbModule::UpdateInternalMetaData
1009//
1010void CordbModule::InitPublicMetaData(TargetBuffer buffer)
1011{
1012 CONTRACTL
1013 {
1014 THROWS;
1015 }
1016 CONTRACTL_END;
1017
1018 INTERNAL_API_ENTRY(this->GetProcess());
1019 LOG((LF_CORDB,LL_INFO100000, "CM::IPM: initing with remote buffer 0x%p length 0x%x\n",
1020 CORDB_ADDRESS_TO_PTR(buffer.pAddress), buffer.cbSize));
1021 ULONG nMetaDataSize = buffer.cbSize;
1022
1023 if (nMetaDataSize == 0)
1024 {
1025 // We should always have metadata, and if we don't, we want to know.
1026 // @dbgtodo metadata - we know metadata from dynamic modules doesn't work in V3
1027 // (non-shim) cases yet.
1028 // But our caller should already have handled that case.
1029 SIMPLIFYING_ASSUMPTION(!"Error: missing the metadata");
1030 return;
1031 }
1032
1033 HRESULT hr = S_OK;
1034
1035 // Get metadata Dispenser.
1036 IMetaDataDispenserEx * pDisp = GetProcess()->GetDispenser();
1037
1038 // copy it over from the remote process
1039
1040 CoTaskMemHolder<VOID> pMetaDataCopy;
1041 CopyRemoteMetaData(buffer, pMetaDataCopy.GetAddr());
1042
1043
1044 //
1045 // Setup our metadata import object, m_pIMImport
1046 //
1047
1048 // Save the old mode for restoration
1049 VARIANT valueOld;
1050 hr = pDisp->GetOption(MetaDataSetUpdate, &valueOld);
1051 SIMPLIFYING_ASSUMPTION(!FAILED(hr));
1052
1053 // Set R/W mode so that we can update the metadata when
1054 // we do EnC operations.
1055 VARIANT valueRW;
1056 V_VT(&valueRW) = VT_UI4;
1057 V_I4(&valueRW) = MDUpdateFull;
1058 hr = pDisp->SetOption(MetaDataSetUpdate, &valueRW);
1059 SIMPLIFYING_ASSUMPTION(!FAILED(hr));
1060
1061 hr = pDisp->OpenScopeOnMemory(pMetaDataCopy,
1062 nMetaDataSize,
1063 ofTakeOwnership,
1064 IID_IMetaDataImport,
1065 reinterpret_cast<IUnknown**>( &m_pIMImport ));
1066
1067 // MetaData has taken ownership -don't free the memory
1068 pMetaDataCopy.SuppressRelease();
1069
1070 // Immediately restore the old setting.
1071 HRESULT hrRestore = pDisp->SetOption(MetaDataSetUpdate, &valueOld);
1072 SIMPLIFYING_ASSUMPTION(!FAILED(hrRestore));
1073
1074 // Throw on errors.
1075 IfFailThrow(hr);
1076 IfFailThrow(hrRestore);
1077
1078 // Done!
1079}
1080
1081//---------------------------------------------------------------------------------------
1082// Update public MetaData by copying it from the target and updating our IMetaDataImport object.
1083//
1084// Arguments:
1085// buffer - buffer into target space containing metadata blob
1086//
1087// Notes:
1088// Useful for additional class-loads into a dynamic module. A new class means new metadata
1089// and so we need to update the RS metadata to stay in sync with the left-side.
1090//
1091// This will call code:CordbModule::CopyRemoteMetaData to copy the remote buffer locally, and then
1092// it can OpenScopeOnMemory().
1093//
1094void CordbModule::UpdatePublicMetaDataFromRemote(TargetBuffer bufferRemoteMetaData)
1095{
1096 CONTRACTL
1097 {
1098 // @dbgtodo metadata - think about the error semantics here. These fails during dispatching an event; so
1099 // address this during event pipeline.
1100 THROWS;
1101 }
1102 CONTRACTL_END;
1103
1104 if (bufferRemoteMetaData.IsEmpty())
1105 {
1106 ThrowHR(E_INVALIDARG);
1107 }
1108
1109 INTERNAL_API_ENTRY(this->GetProcess()); //
1110 LOG((LF_CORDB,LL_INFO100000, "CM::UPMFR: updating with remote buffer 0x%p length 0x%x\n",
1111 CORDB_ADDRESS_TO_PTR(bufferRemoteMetaData.pAddress), bufferRemoteMetaData.cbSize));
1112 // We're re-initializing existing metadata.
1113 _ASSERTE(m_pIMImport != NULL);
1114
1115
1116 HRESULT hr = S_OK;
1117
1118 ULONG dwMetaDataSize = bufferRemoteMetaData.cbSize;
1119
1120 // First copy it from the remote process
1121 CoTaskMemHolder<VOID> pLocalMetaDataPtr;
1122 CopyRemoteMetaData(bufferRemoteMetaData, pLocalMetaDataPtr.GetAddr());
1123
1124 IMetaDataDispenserEx * pDisp = GetProcess()->GetDispenser();
1125 _ASSERTE(pDisp != NULL); // throws on error.
1126
1127 LOG((LF_CORDB,LL_INFO100000, "CM::RI: converting to new metadata\n"));
1128
1129 // now verify that the metadata is valid by opening a temporary scope on the memory
1130 {
1131 ReleaseHolder<IMetaDataImport> pIMImport;
1132 hr = pDisp->OpenScopeOnMemory(pLocalMetaDataPtr,
1133 dwMetaDataSize,
1134 0,
1135 IID_IMetaDataImport,
1136 (IUnknown**)&pIMImport);
1137 IfFailThrow(hr);
1138 }
1139
1140 // We reopen on an existing instance, not create a new instance.
1141 _ASSERTE(m_pIMImport != NULL); //
1142
1143 // Now tell our current IMetaDataImport object to re-initialize by swapping in the new memory block.
1144 // This allows us to keep manipulating metadata objects on other threads without crashing.
1145 // This will also invalidate an existing associated Internal MetaData.
1146 hr = ReOpenMetaDataWithMemoryEx(m_pIMImport, pLocalMetaDataPtr, dwMetaDataSize, ofTakeOwnership );
1147 IfFailThrow(hr);
1148
1149 // Success. MetaData now owns the metadata memory
1150 pLocalMetaDataPtr.SuppressRelease();
1151}
1152
1153//---------------------------------------------------------------------------------------
1154// Copy metadata memory from the remote process into a newly allocated local buffer.
1155//
1156// Arguments:
1157// pRemoteMetaDataPtr - pointer to remote buffer
1158// dwMetaDataSize - size of buffer.
1159// pLocalBuffer - holder to get local buffer.
1160//
1161// Returns:
1162// pLocalBuffer may be allocated.
1163// Throws on error (pLocalBuffer may contain garbage).
1164// Else if successful, pLocalBuffer contains local copy of metadata.
1165//
1166// Notes:
1167// This can copy metadata out for the dynamic case or the normal case.
1168// Uses an allocator (CoTaskMemHolder) that lets us hand off the memory to the metadata.
1169void CordbModule::CopyRemoteMetaData(
1170 TargetBuffer buffer,
1171 CoTaskMemHolder<VOID> * pLocalBuffer)
1172{
1173 CONTRACTL
1174 {
1175 THROWS;
1176 }
1177 CONTRACTL_END;
1178
1179 _ASSERTE(pLocalBuffer != NULL);
1180 _ASSERTE(!buffer.IsEmpty());
1181
1182 // Allocate space for the local copy of the metadata
1183 // No need to zero out the memory since we'll fill it all here.
1184 LPVOID pRawBuffer = CoTaskMemAlloc(buffer.cbSize);
1185 if (pRawBuffer == NULL)
1186 {
1187 ThrowOutOfMemory();
1188 }
1189
1190 pLocalBuffer->Assign(pRawBuffer);
1191
1192
1193
1194 // Copy the metadata from the left side
1195 GetProcess()->SafeReadBuffer(buffer, (BYTE *)pRawBuffer);
1196
1197 return;
1198}
1199
1200HRESULT CordbModule::QueryInterface(REFIID id, void **pInterface)
1201{
1202 if (id == IID_ICorDebugModule)
1203 {
1204 *pInterface = static_cast<ICorDebugModule*>(this);
1205 }
1206 else if (id == IID_ICorDebugModule2)
1207 {
1208 *pInterface = static_cast<ICorDebugModule2*>(this);
1209 }
1210 else if (id == IID_ICorDebugModule3)
1211 {
1212 *pInterface = static_cast<ICorDebugModule3*>(this);
1213 }
1214 else if (id == IID_IUnknown)
1215 {
1216 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugModule*>(this));
1217 }
1218 else
1219 {
1220 *pInterface = NULL;
1221 return E_NOINTERFACE;
1222 }
1223
1224 ExternalAddRef();
1225 return S_OK;
1226}
1227
1228HRESULT CordbModule::GetProcess(ICorDebugProcess **ppProcess)
1229{
1230 PUBLIC_API_ENTRY(this);
1231 FAIL_IF_NEUTERED(this);
1232 VALIDATE_POINTER_TO_OBJECT(ppProcess, ICorDebugProcess **);
1233
1234 *ppProcess = static_cast<ICorDebugProcess*> (GetProcess());
1235 GetProcess()->ExternalAddRef();
1236
1237 return S_OK;
1238}
1239
1240HRESULT CordbModule::GetBaseAddress(CORDB_ADDRESS *pAddress)
1241{
1242 PUBLIC_API_ENTRY(this);
1243 FAIL_IF_NEUTERED(this);
1244 VALIDATE_POINTER_TO_OBJECT(pAddress, CORDB_ADDRESS *);
1245
1246 *pAddress = m_PEBuffer.pAddress;
1247 return S_OK;
1248}
1249
1250HRESULT CordbModule::GetAssembly(ICorDebugAssembly **ppAssembly)
1251{
1252 PUBLIC_API_ENTRY(this);
1253 FAIL_IF_NEUTERED(this);
1254 VALIDATE_POINTER_TO_OBJECT(ppAssembly, ICorDebugAssembly **);
1255
1256 *ppAssembly = static_cast<ICorDebugAssembly *> (m_pAssembly);
1257 if (m_pAssembly != NULL)
1258 {
1259 m_pAssembly->ExternalAddRef();
1260 }
1261
1262 return S_OK;
1263}
1264
1265// Public implementation of ICorDebugModule::GetName,
1266// wrapper around code:GetNameWorker (which throws).
1267HRESULT CordbModule::GetName(ULONG32 cchName, ULONG32 *pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
1268{
1269 HRESULT hr = S_OK;
1270 PUBLIC_API_BEGIN(this)
1271 {
1272 EX_TRY
1273 {
1274 hr = GetNameWorker(cchName, pcchName, szName);
1275 }
1276 EX_CATCH_HRESULT(hr);
1277
1278 // GetNameWorker can use metadata. If it fails due to missing metadata, or if we fail to find expected
1279 // target memory (dump debugging) then we should fall back to getting the file name without metadata.
1280 if ((hr == CORDBG_E_MISSING_METADATA) ||
1281 (hr == CORDBG_E_READVIRTUAL_FAILURE) ||
1282 (hr == HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)))
1283 {
1284 DWORD dwImageTimeStamp = 0; // unused
1285 DWORD dwImageSize = 0; // unused
1286 bool isNGEN = false;
1287 StringCopyHolder filePath;
1288
1289 _ASSERTE(!m_vmPEFile.IsNull());
1290 if (this->GetProcess()->GetDAC()->GetMetaDataFileInfoFromPEFile(m_vmPEFile,
1291 dwImageTimeStamp,
1292 dwImageSize,
1293 isNGEN,
1294 &filePath))
1295 {
1296 _ASSERTE(filePath.IsSet());
1297
1298 // Unfortunately, metadata lookup preferentially takes the ngen image - so in this case,
1299 // we need to go back and get the IL image's name instead.
1300 if ((isNGEN) &&
1301 (this->GetProcess()->GetDAC()->GetILImageInfoFromNgenPEFile(m_vmPEFile,
1302 dwImageTimeStamp,
1303 dwImageSize,
1304 &filePath)))
1305 {
1306 _ASSERTE(filePath.IsSet());
1307 }
1308
1309 hr = CopyOutString(filePath, cchName, pcchName, szName);
1310 }
1311 }
1312 }
1313 PUBLIC_API_END(hr);
1314
1315 return hr;
1316}
1317
1318//---------------------------------------------------------------------------------------
1319// Gets the module pretty name (may be filename or faked up name)
1320//
1321// Arguments:
1322// cchName - count of characters in the szName buffer on input.
1323// *pcchName - Optional Out parameter, which gets set to the fully requested size
1324// (not just how many characters are written).
1325// szName - buffer to get name.
1326//
1327// Returns:
1328// S_OK on success.
1329// S_FALSE if we fabricate the name.
1330// Return failing HR (on common errors) or Throw on exceptional errors.
1331//
1332// Note:
1333// Filename isn't necessarily the same as the module name in the metadata.
1334//
1335HRESULT CordbModule::GetNameWorker(ULONG32 cchName, ULONG32 *pcchName, __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[])
1336{
1337 CONTRACTL
1338 {
1339 THROWS;
1340 }
1341 CONTRACTL_END;
1342 HRESULT hr = S_OK;
1343 const WCHAR * szTempName = NULL;
1344
1345 ALLOW_DATATARGET_MISSING_MEMORY(
1346 szTempName = GetModulePath();
1347 );
1348
1349#if defined(FEATURE_DBGIPC_TRANSPORT_DI)
1350 // To support VS when debugging remotely we act like the Compact Framework and return the assembly name
1351 // when asked for the name of an in-memory module.
1352 if (szTempName == NULL)
1353 {
1354 IMetaDataAssemblyImport *pAssemblyImport = NULL;
1355 if (SUCCEEDED(hr = GetMetaDataImporter()->QueryInterface(IID_IMetaDataAssemblyImport, (void**)&pAssemblyImport)))
1356 {
1357 mdAssembly mda = TokenFromRid(1, mdtAssembly);
1358 hr = pAssemblyImport->GetAssemblyProps(mda, // [IN] The Assembly for which to get the properties.
1359 NULL, // [OUT] Pointer to the Originator blob.
1360 NULL, // [OUT] Count of bytes in the Originator Blob.
1361 NULL, // [OUT] Hash Algorithm.
1362 szName, // [OUT] Buffer to fill with name.
1363 cchName, // [IN] Size of buffer in wide chars.
1364 (ULONG*)pcchName, // [OUT] Actual # of wide chars in name.
1365 NULL, // [OUT] Assembly MetaData.
1366 NULL); // [OUT] Flags.
1367
1368 pAssemblyImport->Release();
1369
1370 return hr;
1371 }
1372
1373 // reset hr
1374 hr = S_OK;
1375 }
1376
1377
1378#endif // FEATURE_DBGIPC_TRANSPORT_DI
1379
1380
1381 EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
1382 {
1383 StringCopyHolder buffer;
1384 // If the module has no file name, then we'll fabricate a fake name
1385 if (!szTempName)
1386 {
1387 // On MiniDumpNormal, if the debugger can't find the module then there's no way we will
1388 // find metadata.
1389 hr = HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
1390
1391 // Tempting to use the metadata-scope name, but that's a regression from Whidbey. For manifest modules,
1392 // the metadata scope name is not initialized with the string the user supplied to create the
1393 // dynamic assembly. So we call into the runtime to use CLR heuristics to get a more accurate name.
1394 m_pProcess->GetDAC()->GetModuleSimpleName(m_vmModule, &buffer);
1395 _ASSERTE(buffer.IsSet());
1396 szTempName = buffer;
1397 // Note that we considered returning S_FALSE for fabricated names like this, but that's a breaking
1398 // change from Whidbey that is known to trigger bugs in vS. If a debugger wants to differentiate
1399 // real path names from fake simple names, we'll just have to add a new API with the right semantics.
1400 }
1401
1402 hr = CopyOutString(szTempName, cchName, pcchName, szName);
1403 }
1404 EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY
1405
1406 return hr;
1407}
1408
1409//---------------------------------------------------------------------------------------
1410// Gets actual name of loaded module. (no faked names)
1411//
1412// Returns:
1413// string for full path to module name. This is a file that can be opened.
1414// NULL if name is not available (such as in some dynamic module cases)
1415// Throws if failed accessing target
1416//
1417// Notes:
1418// We avoid using the method name "GetModuleFileName" because winbase.h #defines that
1419// token (along with many others) to have an A or W suffix.
1420const WCHAR * CordbModule::GetModulePath()
1421{
1422 // Lazily initialize. Module filenames cannot change, and so once
1423 // we've retrieved this successfully, it's stored for good.
1424 if (!m_strModulePath.IsSet())
1425 {
1426 IDacDbiInterface * pDac = m_pProcess->GetDAC(); // throws
1427 pDac->GetModulePath(m_vmModule, &m_strModulePath); // throws
1428 _ASSERTE(m_strModulePath.IsSet());
1429 }
1430
1431 if (m_strModulePath.IsEmpty())
1432 {
1433 return NULL; // module has no filename
1434 }
1435 return m_strModulePath;
1436}
1437
1438//---------------------------------------------------------------------------------------
1439// Get and caches ngen image path.
1440//
1441// Returns:
1442// Null-terminated string to ngen image path.
1443// NULL if there is no ngen filename (eg, file is not ngenned).
1444// Throws on error (such as inability to read the path from the target).
1445//
1446// Notes:
1447// This can be used to get the path to find metadata. For ngenned images,
1448// the IL (and associated metadata) may not be loaded, so we may want to get the
1449// metadata out of the ngen image.
1450const WCHAR * CordbModule::GetNGenImagePath()
1451{
1452 HRESULT hr = S_OK;
1453 EX_TRY
1454 {
1455 // Lazily initialize. Module filenames cannot change, and so once
1456 // we've retrieved this successfully, it's stored for good.
1457 if (!m_strNGenImagePath.IsSet())
1458 {
1459 IDacDbiInterface * pDac = m_pProcess->GetDAC(); // throws
1460 BOOL fNonEmpty = pDac->GetModuleNGenPath(m_vmModule, &m_strNGenImagePath); // throws
1461 (void)fNonEmpty; //prevent "unused variable" error from GCC
1462 _ASSERTE(m_strNGenImagePath.IsSet() && (m_strNGenImagePath.IsEmpty() == !fNonEmpty));
1463 }
1464 }
1465 EX_CATCH_HRESULT(hr);
1466
1467 if (FAILED(hr) ||
1468 m_strNGenImagePath == NULL ||
1469 m_strNGenImagePath.IsEmpty())
1470 {
1471 return NULL; // module has no ngen filename
1472 }
1473 return m_strNGenImagePath;
1474}
1475
1476// Implementation of ICorDebugModule::EnableJITDebugging
1477// See also code:CordbModule::SetJITCompilerFlags
1478HRESULT CordbModule::EnableJITDebugging(BOOL bTrackJITInfo, BOOL bAllowJitOpts)
1479{
1480 // Leftside will enforce that this is a valid time to change jit flags.
1481 // V1.0 behavior allowed setting these in the middle of a module's lifetime, which meant
1482 // that different methods throughout the module may have been jitted differently.
1483 // Since V2, this has to be set when the module is first loaded, before anything is jitted.
1484
1485 PUBLIC_API_ENTRY(this);
1486 FAIL_IF_NEUTERED(this);
1487
1488 DWORD dwFlags = CORDEBUG_JIT_DEFAULT;
1489
1490 // Since V2, bTrackJITInfo is the default and cannot be turned off.
1491 if (!bAllowJitOpts)
1492 {
1493 dwFlags |= CORDEBUG_JIT_DISABLE_OPTIMIZATION;
1494 }
1495 return SetJITCompilerFlags(dwFlags);
1496}
1497
1498HRESULT CordbModule::EnableClassLoadCallbacks(BOOL bClassLoadCallbacks)
1499{
1500 PUBLIC_API_ENTRY(this);
1501 FAIL_IF_NEUTERED(this);
1502 ATT_ALLOW_LIVE_DO_STOPGO(GetProcess());
1503
1504 // You must receive ClassLoad callbacks for dynamic modules so that we can keep the metadata up-to-date on the Right
1505 // Side. Therefore, we refuse to turn them off for all dynamic modules (they were forced on when the module was
1506 // loaded on the Left Side.)
1507 if (m_fDynamic && !bClassLoadCallbacks)
1508 return E_INVALIDARG;
1509
1510 if (m_vmDomainFile.IsNull())
1511 return E_UNEXPECTED;
1512
1513 // Send a Set Class Load Flag event to the left side. There is no need to wait for a response, and this can be
1514 // called whether or not the process is synchronized.
1515 CordbProcess *pProcess = GetProcess();
1516
1517 DebuggerIPCEvent event;
1518 pProcess->InitIPCEvent(&event,
1519 DB_IPCE_SET_CLASS_LOAD_FLAG,
1520 false,
1521 (GetAppDomain()->GetADToken()));
1522 event.SetClassLoad.vmDomainFile = this->m_vmDomainFile;
1523 event.SetClassLoad.flag = (bClassLoadCallbacks == TRUE);
1524
1525 HRESULT hr = pProcess->m_cordb->SendIPCEvent(pProcess, &event,
1526 sizeof(DebuggerIPCEvent));
1527 hr = WORST_HR(hr, event.hr);
1528 return hr;
1529}
1530
1531//-----------------------------------------------------------------------------
1532// Public implementation of ICorDebugModule::GetFunctionFromToken
1533// Get the CordbFunction matches this token / module pair.
1534// Each time a function is Enc-ed, it gets its own CordbFunction object.
1535// This will return the latest EnC version of the function for this Module,Token pair.
1536HRESULT CordbModule::GetFunctionFromToken(mdMethodDef token,
1537 ICorDebugFunction **ppFunction)
1538{
1539 // This is not reentrant. DBI should call code:CordbModule::LookupOrCreateFunctionLatestVersion instead.
1540 PUBLIC_API_ENTRY(this);
1541 ATT_ALLOW_LIVE_DO_STOPGO(GetProcess()); // @todo - can this be RequiredStop?
1542
1543
1544 FAIL_IF_NEUTERED(this);
1545 VALIDATE_POINTER_TO_OBJECT(ppFunction, ICorDebugFunction **);
1546
1547 HRESULT hr = S_OK;
1548 EX_TRY
1549 {
1550 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1551
1552 // Check token is valid.
1553 if ((token == mdMethodDefNil) ||
1554 (!GetMetaDataImporter()->IsValidToken(token)))
1555 {
1556 ThrowHR(E_INVALIDARG);
1557 }
1558
1559 CordbFunction * pFunction = LookupOrCreateFunctionLatestVersion(token);
1560
1561 *ppFunction = static_cast<ICorDebugFunction*> (pFunction);
1562 pFunction->ExternalAddRef();
1563
1564 }
1565 EX_CATCH_HRESULT(hr);
1566 return hr;
1567}
1568
1569HRESULT CordbModule::GetFunctionFromRVA(CORDB_ADDRESS rva,
1570 ICorDebugFunction **ppFunction)
1571{
1572 PUBLIC_API_ENTRY(this);
1573 FAIL_IF_NEUTERED(this);
1574 VALIDATE_POINTER_TO_OBJECT(ppFunction, ICorDebugFunction **);
1575
1576 return E_NOTIMPL;
1577}
1578
1579HRESULT CordbModule::LookupClassByToken(mdTypeDef token,
1580 CordbClass **ppClass)
1581{
1582 INTERNAL_API_ENTRY(this->GetProcess()); //
1583 FAIL_IF_NEUTERED(this);
1584
1585 HRESULT hr = S_OK;
1586 EX_TRY // @dbgtodo exceptions - push this up
1587 {
1588 *ppClass = NULL;
1589
1590 if ((token == mdTypeDefNil) || (TypeFromToken(token) != mdtTypeDef))
1591 {
1592 ThrowHR(E_INVALIDARG);
1593 }
1594
1595 RSLockHolder lockHolder(GetProcess()->GetProcessLock()); // @dbgtodo synchronization - Push this up
1596
1597 CordbClass *pClass = m_classes.GetBase(token);
1598 if (pClass == NULL)
1599 {
1600 // Validate the token.
1601 if (!GetMetaDataImporter()->IsValidToken(token))
1602 {
1603 ThrowHR(E_INVALIDARG);
1604 }
1605
1606 RSInitHolder<CordbClass> pClassInit(new CordbClass(this, token));
1607 pClass = pClassInit.TransferOwnershipToHash(&m_classes);
1608 }
1609
1610 *ppClass = pClass;
1611
1612 }
1613 EX_CATCH_HRESULT(hr);
1614 return hr;
1615}
1616
1617HRESULT CordbModule::GetClassFromToken(mdTypeDef token,
1618 ICorDebugClass **ppClass)
1619{
1620 PUBLIC_API_ENTRY(this);
1621 FAIL_IF_NEUTERED(this);
1622 ATT_ALLOW_LIVE_DO_STOPGO(this->GetProcess()); // @todo - could this be RequiredStopped?
1623 VALIDATE_POINTER_TO_OBJECT(ppClass, ICorDebugClass **);
1624
1625 HRESULT hr = S_OK;
1626 EX_TRY
1627 {
1628 CordbClass *pClass = NULL;
1629 *ppClass = NULL;
1630
1631 // Validate the token.
1632 if (!GetMetaDataImporter()->IsValidToken(token))
1633 {
1634 ThrowHR(E_INVALIDARG);
1635 }
1636
1637 hr = LookupClassByToken(token, &pClass);
1638 IfFailThrow(hr);
1639
1640 *ppClass = static_cast<ICorDebugClass*> (pClass);
1641 pClass->ExternalAddRef();
1642 }
1643 EX_CATCH_HRESULT(hr);
1644 return hr;
1645}
1646
1647HRESULT CordbModule::CreateBreakpoint(ICorDebugModuleBreakpoint **ppBreakpoint)
1648{
1649 PUBLIC_API_ENTRY(this);
1650 FAIL_IF_NEUTERED(this);
1651 VALIDATE_POINTER_TO_OBJECT(ppBreakpoint, ICorDebugModuleBreakpoint **);
1652
1653 return E_NOTIMPL;
1654}
1655
1656//
1657// Return the token for the Module table entry for this object. The token
1658// may then be passed to the meta data import api's.
1659//
1660HRESULT CordbModule::GetToken(mdModule *pToken)
1661{
1662 PUBLIC_API_ENTRY(this);
1663 FAIL_IF_NEUTERED(this);
1664 VALIDATE_POINTER_TO_OBJECT(pToken, mdModule *);
1665
1666 HRESULT hr = S_OK;
1667 EX_TRY
1668 {
1669 hr = GetMetaDataImporter()->GetModuleFromScope(pToken);
1670 IfFailThrow(hr);
1671 }
1672 EX_CATCH_HRESULT(hr);
1673 return hr;
1674}
1675
1676
1677// public implementation for ICorDebugModule::GetMetaDataInterface
1678// Return a meta data interface pointer that can be used to examine the
1679// meta data for this module.
1680HRESULT CordbModule::GetMetaDataInterface(REFIID riid, IUnknown **ppObj)
1681{
1682 PUBLIC_API_ENTRY(this);
1683 FAIL_IF_NEUTERED(this);
1684 VALIDATE_POINTER_TO_OBJECT(ppObj, IUnknown **);
1685
1686 HRESULT hr = S_OK;
1687 EX_TRY
1688 {
1689 // QI the importer that we already have and return the result.
1690 hr = GetMetaDataImporter()->QueryInterface(riid, (void**)ppObj);
1691 IfFailThrow(hr);
1692 }
1693 EX_CATCH_HRESULT(hr);
1694
1695 return hr;
1696}
1697
1698//-----------------------------------------------------------------------------
1699// LookupFunctionLatestVersion finds the latest cached version of an existing CordbFunction
1700// in the given module. If the function doesn't exist, it returns NULL.
1701//
1702// Arguments:
1703// funcMetaDataToken - methoddef token for function to lookup
1704//
1705//
1706// Notes:
1707// If no CordbFunction instance was cached, then this returns NULL.
1708// use code:CordbModule::LookupOrCreateFunctionLatestVersion to do a lookup that will
1709// populate the cache if needed.
1710CordbFunction* CordbModule::LookupFunctionLatestVersion(mdMethodDef funcMetaDataToken)
1711{
1712 INTERNAL_API_ENTRY(this);
1713 return m_functions.GetBase(funcMetaDataToken);
1714}
1715
1716
1717//-----------------------------------------------------------------------------
1718// Lookup (or create) the CordbFunction for the latest EnC version.
1719//
1720// Arguments:
1721// funcMetaDataToken - methoddef token for function to lookup
1722//
1723// Returns:
1724// CordbFunction instance for that token. This will create an instance if needed, and so never returns null.
1725// Throws on critical error.
1726//
1727// Notes:
1728// This creates the latest EnC version. Use code:CordbModule::LookupOrCreateFunction to do an
1729// enc-version aware function lookup.
1730//
1731CordbFunction* CordbModule::LookupOrCreateFunctionLatestVersion(mdMethodDef funcMetaDataToken)
1732{
1733 INTERNAL_API_ENTRY(this);
1734 CordbFunction * pFunction = m_functions.GetBase(funcMetaDataToken);
1735 if (pFunction != NULL)
1736 {
1737 return pFunction;
1738 }
1739
1740 // EnC adds each version to the hash. So if the hash lookup fails, then it must not be an EnC case,
1741 // and so we can use the default version number.
1742 return CreateFunction(funcMetaDataToken, CorDB_DEFAULT_ENC_FUNCTION_VERSION);
1743}
1744
1745//-----------------------------------------------------------------------------
1746// LookupOrCreateFunction finds an existing version of CordbFunction in the given module.
1747// If the function doesn't exist, it creates it.
1748//
1749// The outgoing function is not yet fully inititalized. For eg, the Class field is not set.
1750// However, ICorDebugFunction::GetClass() will check that and lazily initialize the field.
1751//
1752// Throws on error.
1753//
1754CordbFunction * CordbModule::LookupOrCreateFunction(mdMethodDef funcMetaDataToken, SIZE_T enCVersion)
1755{
1756 INTERNAL_API_ENTRY(this);
1757
1758 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
1759
1760 CordbFunction * pFunction = m_functions.GetBase(funcMetaDataToken);
1761
1762 // special case non-existance as need to add to the hash table too
1763 if (pFunction == NULL)
1764 {
1765 // EnC adds each version to the hash. So if the hash lookup fails,
1766 // then it must not be an EnC case.
1767 return CreateFunction(funcMetaDataToken, enCVersion);
1768 }
1769
1770 // linked list sorted with most recent version at front. Version numbers correspond
1771 // to actual edit count against the module, so version numbers not necessarily contiguous.
1772 // Any valid EnC version must already exist as we would have created it on the ApplyChanges
1773 for (CordbFunction *pf=pFunction; pf != NULL; pf = pf->GetPrevVersion())
1774 {
1775 if (pf->GetEnCVersionNumber() == enCVersion)
1776 {
1777 return pf;
1778 }
1779 }
1780
1781 _ASSERTE(!"Couldn't find EnC version of function\n");
1782 ThrowHR(E_FAIL);
1783}
1784
1785HRESULT CordbModule::IsDynamic(BOOL *pDynamic)
1786{
1787 PUBLIC_API_ENTRY(this);
1788 FAIL_IF_NEUTERED(this);
1789 VALIDATE_POINTER_TO_OBJECT(pDynamic, BOOL *);
1790
1791 (*pDynamic) = m_fDynamic;
1792
1793 return S_OK;
1794}
1795
1796BOOL CordbModule::IsDynamic()
1797{
1798 return m_fDynamic;
1799}
1800
1801
1802HRESULT CordbModule::IsInMemory(BOOL *pInMemory)
1803{
1804 PUBLIC_API_ENTRY(this);
1805 FAIL_IF_NEUTERED(this);
1806 VALIDATE_POINTER_TO_OBJECT(pInMemory, BOOL *);
1807
1808 (*pInMemory) = m_fInMemory;
1809
1810 return S_OK;
1811}
1812
1813HRESULT CordbModule::GetGlobalVariableValue(mdFieldDef fieldDef,
1814 ICorDebugValue **ppValue)
1815{
1816 PUBLIC_API_ENTRY(this);
1817 FAIL_IF_NEUTERED(this);
1818 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
1819 ATT_REQUIRE_STOPPED_MAY_FAIL(this->GetProcess());
1820
1821 HRESULT hr = S_OK;
1822 EX_TRY
1823 {
1824
1825 if (m_pClass == NULL)
1826 {
1827 CordbClass * pGlobalClass = NULL;
1828 hr = LookupClassByToken(COR_GLOBAL_PARENT_TOKEN, &pGlobalClass);
1829 IfFailThrow(hr);
1830
1831 m_pClass.Assign(pGlobalClass);
1832 _ASSERTE(m_pClass != NULL);
1833 }
1834
1835 hr = m_pClass->GetStaticFieldValue(fieldDef, NULL, ppValue);
1836 IfFailThrow(hr);
1837 }
1838 EX_CATCH_HRESULT(hr);
1839 return hr;
1840}
1841
1842
1843
1844//
1845// CreateFunction creates a new function from the given information and
1846// adds it to the module.
1847//
1848CordbFunction * CordbModule::CreateFunction(mdMethodDef funcMetaDataToken, SIZE_T enCVersion)
1849{
1850 INTERNAL_API_ENTRY(this);
1851
1852 // In EnC cases, the token may not yet be valid. We may be caching the CordbFunction
1853 // for a token for an added method before the metadata is updated on the RS.
1854 // We rely that our caller has done token validation.
1855
1856 // Create a new CordbFunction object or throw.
1857 RSInitHolder<CordbFunction> pFunction(new CordbFunction(this, funcMetaDataToken, enCVersion)); // throws
1858 CordbFunction * pCopy = pFunction.TransferOwnershipToHash(&m_functions);
1859 return pCopy;
1860}
1861
1862#ifdef EnC_SUPPORTED
1863//---------------------------------------------------------------------------------------
1864//
1865// Creates a new CordbFunction object to represent this new version of a function and
1866// updates the module's function collection to mark this as the latest version.
1867//
1868// Arguments:
1869// funcMetaDataToken - the functions methodDef token in this module
1870// enCVerison - The new version number of this function
1871// ppFunction - Output param for the new instance - optional
1872//
1873// Assumptions:
1874// Assumes the specified version of this function doesn't already exist (i.e. enCVersion
1875// is newer than all existing versions).
1876//
1877HRESULT CordbModule::UpdateFunction(mdMethodDef funcMetaDataToken,
1878 SIZE_T enCVersion,
1879 CordbFunction** ppFunction)
1880{
1881 INTERNAL_API_ENTRY(this);
1882 if (ppFunction)
1883 *ppFunction = NULL;
1884
1885 _ASSERTE(funcMetaDataToken);
1886
1887 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1888
1889 // pOldVersion is the 2nd newest version
1890 CordbFunction* pOldVersion = LookupFunctionLatestVersion(funcMetaDataToken);
1891
1892 // if don't have an old version, then create a default versioned one as will most likely
1893 // go looking for it later and easier to put it in now than have code to insert it later.
1894 if (!pOldVersion)
1895 {
1896 LOG((LF_ENC, LL_INFO10000, "CM::UF: adding %8.8x with version %d\n", funcMetaDataToken, enCVersion));
1897 HRESULT hr = S_OK;
1898 EX_TRY
1899 {
1900 pOldVersion = CreateFunction(funcMetaDataToken, CorDB_DEFAULT_ENC_FUNCTION_VERSION);
1901 }
1902 EX_CATCH_HRESULT(hr);
1903 if (FAILED(hr))
1904 {
1905 return hr;
1906 }
1907 }
1908
1909 // This method should not be called for versions that already exist
1910 _ASSERTE( enCVersion > pOldVersion->GetEnCVersionNumber());
1911
1912 LOG((LF_ENC, LL_INFO10000, "CM::UF: updating %8.8x with version %d\n", funcMetaDataToken, enCVersion));
1913 // Create a new function object.
1914 CordbFunction * pNewVersion = new (nothrow) CordbFunction(this, funcMetaDataToken, enCVersion);
1915
1916 if (pNewVersion == NULL)
1917 return E_OUTOFMEMORY;
1918
1919 // Chain the 2nd most recent version onto this instance (this will internal addref).
1920 pNewVersion->SetPrevVersion(pOldVersion);
1921
1922 // Add the function to the Module's hash of all functions.
1923 HRESULT hr = m_functions.SwapBase(pOldVersion, pNewVersion);
1924
1925 if (FAILED(hr))
1926 {
1927 delete pNewVersion;
1928 return hr;
1929 }
1930
1931 // Do cleanup for function which is no longer the latest version
1932 pNewVersion->GetPrevVersion()->MakeOld();
1933
1934 if (ppFunction)
1935 *ppFunction = pNewVersion;
1936
1937 return hr;
1938}
1939#endif // EnC_SUPPORTED
1940
1941
1942HRESULT CordbModule::LookupOrCreateClass(mdTypeDef classMetaDataToken,CordbClass** ppClass)
1943{
1944 INTERNAL_API_ENTRY(this);
1945 FAIL_IF_NEUTERED(this);
1946
1947 RSLockHolder lockHolder(GetProcess()->GetProcessLock()); // @dbgtodo exceptions synchronization-
1948 // Push this lock up, convert to exceptions.
1949
1950 HRESULT hr = S_OK;
1951 *ppClass = LookupClass(classMetaDataToken);
1952 if (*ppClass == NULL)
1953 {
1954 hr = CreateClass(classMetaDataToken,ppClass);
1955 if (!SUCCEEDED(hr))
1956 {
1957 return hr;
1958 }
1959 _ASSERTE(*ppClass != NULL);
1960 }
1961 return hr;
1962}
1963
1964//
1965// LookupClass finds an existing CordbClass in the given module.
1966// If the class doesn't exist, it returns NULL.
1967//
1968CordbClass* CordbModule::LookupClass(mdTypeDef classMetaDataToken)
1969{
1970 INTERNAL_API_ENTRY(this);
1971 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
1972 return m_classes.GetBase(classMetaDataToken);
1973}
1974
1975//
1976// CreateClass creates a new class from the given information and
1977// adds it to the module.
1978//
1979HRESULT CordbModule::CreateClass(mdTypeDef classMetaDataToken,
1980 CordbClass** ppClass)
1981{
1982 INTERNAL_API_ENTRY(this);
1983 FAIL_IF_NEUTERED(this);
1984
1985 _ASSERTE(GetProcess()->ThreadHoldsProcessLock());
1986
1987 CordbClass* pClass = new (nothrow) CordbClass(this, classMetaDataToken);
1988
1989 if (pClass == NULL)
1990 return E_OUTOFMEMORY;
1991
1992 HRESULT hr = m_classes.AddBase(pClass);
1993
1994 if (SUCCEEDED(hr))
1995 *ppClass = pClass;
1996 else
1997 delete pClass;
1998
1999 if (classMetaDataToken == COR_GLOBAL_PARENT_TOKEN)
2000 {
2001 _ASSERTE( m_pClass == NULL ); //redundant create
2002 m_pClass.Assign(pClass);
2003 }
2004
2005 return hr;
2006}
2007
2008
2009// Resolve a type-ref from this module to a CordbClass
2010//
2011// Arguments:
2012// token - a Type Ref in this module's scope.
2013// ppClass - out parameter to get the class we resolve to.
2014//
2015// Returns:
2016// S_OK on success.
2017// CORDBG_E_CLASS_NOT_LOADED is the TypeRef is not yet resolved because the type it will refer
2018// to is not yet loaded.
2019//
2020// Notes:
2021// In general, a TypeRef refers to a type in another module. (Although as a corner case, it could
2022// refer to this module too). This resolves a TypeRef within the current module's scope to a
2023// (TypeDef, metadata scope), which is in turn encapsulated as a CordbClass.
2024//
2025// A TypeRef has a resolution scope (ModuleRef or AssemblyRef) and string name for the type
2026// within that scope. Resolving means:
2027// 1. Determining the actual metadata scope loaded for the resolution scope.
2028// See also code:CordbModule::ResolveAssemblyInternal
2029// If the resolved module hasn't been loaded yet, the resolution will fail.
2030// 2. Doing a string lookup of the TypeRef's name within that resolved scope to find the TypeDef.
2031// 3. Returning the (resolved scope, TypeDef) pair.
2032//
2033HRESULT CordbModule::ResolveTypeRef(mdTypeRef token, CordbClass **ppClass)
2034{
2035 FAIL_IF_NEUTERED(this);
2036 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
2037
2038 CordbProcess * pProcess = GetProcess();
2039
2040 _ASSERTE((pProcess->GetShim() == NULL) || pProcess->GetSynchronized());
2041
2042
2043 if ((token == mdTypeRefNil) || (TypeFromToken(token) != mdtTypeRef))
2044 {
2045 return E_INVALIDARG;
2046 }
2047
2048 if (m_vmDomainFile.IsNull() || m_pAppDomain == NULL)
2049 {
2050 return E_UNEXPECTED;
2051 }
2052
2053 HRESULT hr = S_OK;
2054 *ppClass = NULL;
2055 EX_TRY
2056 {
2057 TypeRefData inData = {m_vmDomainFile, token};
2058 TypeRefData outData;
2059
2060 {
2061 RSLockHolder lockHolder(pProcess->GetProcessLock());
2062 pProcess->GetDAC()->ResolveTypeReference(&inData, &outData);
2063 }
2064
2065 CordbModule * pModule = m_pAppDomain->LookupOrCreateModule(outData.vmDomainFile);
2066 IfFailThrow(pModule->LookupClassByToken(outData.typeToken, ppClass));
2067 }
2068 EX_CATCH_HRESULT(hr);
2069
2070 return hr;
2071
2072} // CordbModule::ResolveTypeRef
2073
2074// Resolve a type ref or def to a CordbClass
2075//
2076// Arguments:
2077// token - a mdTypeDef or mdTypeRef in this module's scope to be resolved
2078// ppClass - out parameter to get the CordbClass for this type
2079//
2080// Notes:
2081// See code:CordbModule::ResolveTypeRef for more details.
2082HRESULT CordbModule::ResolveTypeRefOrDef(mdToken token, CordbClass **ppClass)
2083{
2084 FAIL_IF_NEUTERED(this);
2085 INTERNAL_SYNC_API_ENTRY(this->GetProcess()); //
2086
2087 if ((token == mdTypeRefNil) ||
2088 (TypeFromToken(token) != mdtTypeRef && TypeFromToken(token) != mdtTypeDef))
2089 return E_INVALIDARG;
2090
2091 if (TypeFromToken(token)==mdtTypeRef)
2092 {
2093 // It's a type-ref. That means the type is defined in another module.
2094 // That other module is determined at runtime by Fusion / Loader policy. So we need to
2095 // ultimately ask the runtime which module was actually loaded.
2096 return ( ResolveTypeRef(token, ppClass) );
2097 }
2098 else
2099 {
2100 // It's a type-def. This is the easy case because the type is defined in this same module.
2101 return ( LookupClassByToken(token, ppClass) );
2102 }
2103
2104}
2105
2106//
2107// GetSize returns the size of the module.
2108//
2109HRESULT CordbModule::GetSize(ULONG32 *pcBytes)
2110{
2111 PUBLIC_API_ENTRY(this);
2112 FAIL_IF_NEUTERED(this);
2113 VALIDATE_POINTER_TO_OBJECT(pcBytes, ULONG32 *);
2114
2115 *pcBytes = m_PEBuffer.cbSize;
2116
2117 return S_OK;
2118}
2119
2120CordbAssembly *CordbModule::GetCordbAssembly()
2121{
2122 INTERNAL_API_ENTRY(this);
2123 return m_pAssembly;
2124}
2125
2126
2127// This is legacy from the aborted V1 EnC attempt - not used in V2 EnC support
2128HRESULT CordbModule::GetEditAndContinueSnapshot(
2129 ICorDebugEditAndContinueSnapshot **ppEditAndContinueSnapshot)
2130{
2131 return E_NOTIMPL;
2132}
2133
2134
2135//---------------------------------------------------------------------------------------
2136//
2137// Requests that an edit be applied to the module for edit and continue and updates
2138// the right-side state and metadata.
2139//
2140// Arguments:
2141// cbMetaData - number of bytes in pbMetaData
2142// pbMetaData - a delta metadata blob describing the metadata edits to be made
2143// cbIL - number of bytes in pbIL
2144// pbIL - a new method body stream containing all of the method body information
2145// (IL, EH info, etc) for edited and added methods.
2146//
2147// Return Value:
2148// S_OK on success, various errors on failure
2149//
2150// Notes:
2151//
2152//
2153// This applies the same changes to the RS's copy of the metadata that the left-side will apply to
2154// it's copy of the metadata. see code:EditAndContinueModule::ApplyEditAndContinue
2155//
2156HRESULT CordbModule::ApplyChanges(ULONG cbMetaData,
2157 BYTE pbMetaData[],
2158 ULONG cbIL,
2159 BYTE pbIL[])
2160{
2161 PUBLIC_API_ENTRY(this);
2162 FAIL_IF_NEUTERED(this);
2163 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2164
2165#ifdef EnC_SUPPORTED
2166 // We enable EnC back in code:CordbModule::SetJITCompilerFlags.
2167 // If EnC isn't enabled, then we'll fail in the LS when we try to ApplyChanges.
2168 // We'd expect a well-behaved debugger to never actually land here.
2169
2170
2171 LOG((LF_CORDB,LL_INFO10000, "CP::AC: applying changes"));
2172
2173 VALIDATE_POINTER_TO_OBJECT_ARRAY(pbMetaData,
2174 BYTE,
2175 cbMetaData,
2176 true,
2177 true);
2178 VALIDATE_POINTER_TO_OBJECT_ARRAY(pbIL,
2179 BYTE,
2180 cbIL,
2181 true,
2182 true);
2183
2184 HRESULT hr;
2185 RSExtSmartPtr<IUnknown> pUnk;
2186 RSExtSmartPtr<IMDInternalImport> pMDImport;
2187 RSExtSmartPtr<IMDInternalImport> pMDImport2;
2188
2189 //
2190 // Edit was successful - update the right-side state to reflect the edit
2191 //
2192
2193 ++m_EnCCount;
2194
2195 // apply the changes to our copy of the metadata
2196
2197 _ASSERTE(m_pIMImport != NULL); // must have metadata at this point in EnC
2198 IfFailGo(m_pIMImport->QueryInterface(IID_IUnknown, (void**)&pUnk));
2199
2200 IfFailGo(GetMDInternalInterfaceFromPublic(pUnk, IID_IMDInternalImport,
2201 (void **)&pMDImport));
2202
2203 // The left-side will call this same method on its copy of the metadata.
2204 hr = pMDImport->ApplyEditAndContinue(pbMetaData, cbMetaData, &pMDImport2);
2205 if (pMDImport2 != NULL)
2206 {
2207 // ApplyEditAndContinue() expects IMDInternalImport**, but we give it RSExtSmartPtr<IMDInternalImport>
2208 // Silent cast of RSExtSmartPtr to IMDInternalImport* leads to assignment of a raw pointer
2209 // without calling AddRef(), thus we need to do it manually.
2210
2211 // @todo - ApplyEditAndContinue should probably AddRef the out parameter.
2212 pMDImport2->AddRef();
2213 }
2214 IfFailGo(hr);
2215
2216
2217 // We're about to get a new importer object, so release the old one.
2218 m_pIMImport.Clear();
2219 IfFailGo(GetMDPublicInterfaceFromInternal(pMDImport2, IID_IMetaDataImport, (void **)&m_pIMImport));
2220 // set the new RVA value
2221
2222 // Send the delta over to the debugee and request that it apply the edit
2223 IfFailGo( ApplyChangesInternal(cbMetaData, pbMetaData, cbIL, pbIL) );
2224
2225 EX_TRY
2226 {
2227
2228 m_pInternalMetaDataImport.Clear();
2229 UpdateInternalMetaData();
2230 }
2231 EX_CATCH_HRESULT(hr);
2232 _ASSERTE(SUCCEEDED(hr));
2233
2234ErrExit:
2235 // MetaData interface pointers will be automatically released via SmartPtr dtors.
2236
2237 // @todo : prevent further execution of program
2238 return hr;
2239#else
2240 return E_NOTIMPL;
2241#endif
2242}
2243
2244
2245
2246
2247//---------------------------------------------------------------------------------------
2248//
2249// Requests that an edit be applied to the module for edit and continue and updates
2250// some right-side state, but does not update our copy of the metadata.
2251//
2252// Arguments:
2253// cbMetaData - number of bytes in pbMetaData
2254// pbMetaData - a delta metadata blob describing the metadata edits to be made
2255// cbIL - number of bytes in pbIL
2256// pbIL - a new method body stream containing all of the method body information
2257// (IL, EH info, etc) for edited and added methods.
2258//
2259// Return Value:
2260// S_OK on success, various errors on failure
2261//
2262HRESULT CordbModule::ApplyChangesInternal(ULONG cbMetaData,
2263 BYTE pbMetaData[],
2264 ULONG cbIL,
2265 BYTE pbIL[])
2266{
2267 CONTRACTL
2268 {
2269 NOTHROW;
2270 }
2271 CONTRACTL_END;
2272
2273 LOG((LF_ENC,LL_INFO100, "CordbProcess::ApplyChangesInternal\n"));
2274
2275 FAIL_IF_NEUTERED(this);
2276 INTERNAL_SYNC_API_ENTRY(this->GetProcess()); //
2277
2278 if (m_vmDomainFile.IsNull())
2279 return E_UNEXPECTED;
2280
2281#ifdef EnC_SUPPORTED
2282 HRESULT hr;
2283
2284 void * pRemoteBuf = NULL;
2285
2286 EX_TRY
2287 {
2288
2289 // Create and initialize the event as synchronous
2290 // We'll be sending a NULL appdomain pointer since the individual modules
2291 // will contains pointers to their respective A.D.s
2292 DebuggerIPCEvent event;
2293 GetProcess()->InitIPCEvent(&event, DB_IPCE_APPLY_CHANGES, false, VMPTR_AppDomain::NullPtr());
2294
2295 event.ApplyChanges.vmDomainFile = this->m_vmDomainFile;
2296
2297 // Have the left-side create a buffer for us to store the delta into
2298 ULONG cbSize = cbMetaData+cbIL;
2299 TargetBuffer tbFull = GetProcess()->GetRemoteBuffer(cbSize);
2300 pRemoteBuf = CORDB_ADDRESS_TO_PTR(tbFull.pAddress);
2301
2302 TargetBuffer tbMetaData = tbFull.SubBuffer(0, cbMetaData); // 1st half
2303 TargetBuffer tbIL = tbFull.SubBuffer(cbMetaData); // 2nd half
2304
2305 // Copy the delta metadata over to the debugee
2306
2307 GetProcess()->SafeWriteBuffer(tbMetaData, pbMetaData); // throws
2308 GetProcess()->SafeWriteBuffer(tbIL, pbIL); // throws
2309
2310 // Send a synchronous event requesting the debugee apply the edit
2311 event.ApplyChanges.pDeltaMetadata = tbMetaData.pAddress;
2312 event.ApplyChanges.cbDeltaMetadata = tbMetaData.cbSize;
2313 event.ApplyChanges.pDeltaIL = tbIL.pAddress;
2314 event.ApplyChanges.cbDeltaIL = tbIL.cbSize;
2315
2316 LOG((LF_ENC,LL_INFO100, "CordbProcess::ApplyChangesInternal sending event\n"));
2317 hr = GetProcess()->SendIPCEvent(&event, sizeof(event));
2318 hr = WORST_HR(hr, event.hr);
2319 IfFailThrow(hr);
2320
2321 // Allocate space for the return event.
2322 // We always copy over the whole buffer size which is bigger than sizeof(DebuggerIPCEvent)
2323 // This seems ugly, in this case we know the exact size of the event we want to read
2324 // why copy over all the extra data?
2325 DebuggerIPCEvent *retEvent = (DebuggerIPCEvent *) _alloca(CorDBIPC_BUFFER_SIZE);
2326
2327 {
2328 //
2329 // Wait for events to return from the RC. We expect zero or more add field,
2330 // add function or update function events and one completion event.
2331 //
2332 while (TRUE)
2333 {
2334 hr = GetProcess()->m_cordb->WaitForIPCEventFromProcess(GetProcess(),
2335 GetAppDomain(),
2336 retEvent);
2337 IfFailThrow(hr);
2338
2339 if (retEvent->type == DB_IPCE_APPLY_CHANGES_RESULT)
2340 {
2341 // Done receiving update events
2342 hr = retEvent->ApplyChangesResult.hr;
2343 LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: EnC apply changes result %8.8x.\n", hr));
2344 break;
2345 }
2346
2347 _ASSERTE(retEvent->type == DB_IPCE_ENC_UPDATE_FUNCTION ||
2348 retEvent->type == DB_IPCE_ENC_ADD_FUNCTION ||
2349 retEvent->type == DB_IPCE_ENC_ADD_FIELD);
2350 LOG((LF_CORDB, LL_INFO1000, "[%x] RCET::DRCE: EnC %s %8.8x to version %d.\n",
2351 GetCurrentThreadId(),
2352 retEvent->type == DB_IPCE_ENC_UPDATE_FUNCTION ? "Update function" :
2353 retEvent->type == DB_IPCE_ENC_ADD_FUNCTION ? "Add function" : "Add field",
2354 retEvent->EnCUpdate.memberMetadataToken, retEvent->EnCUpdate.newVersionNumber));
2355
2356 CordbAppDomain *pAppDomain = GetAppDomain();
2357 _ASSERTE(NULL != pAppDomain);
2358 CordbModule* pModule = NULL;
2359
2360
2361 pModule = pAppDomain->LookupOrCreateModule(retEvent->EnCUpdate.vmDomainFile); // throws
2362 _ASSERTE(pModule != NULL);
2363
2364 // update to the newest version
2365
2366 if (retEvent->type == DB_IPCE_ENC_UPDATE_FUNCTION ||
2367 retEvent->type == DB_IPCE_ENC_ADD_FUNCTION)
2368 {
2369 // Update the function collection to reflect this edit
2370 hr = pModule->UpdateFunction(retEvent->EnCUpdate.memberMetadataToken, retEvent->EnCUpdate.newVersionNumber, NULL);
2371
2372 }
2373 // mark the class and relevant type as old so we update it next time we try to query it
2374 if (retEvent->type == DB_IPCE_ENC_ADD_FUNCTION ||
2375 retEvent->type == DB_IPCE_ENC_ADD_FIELD)
2376 {
2377 RSLockHolder lockHolder(GetProcess()->GetProcessLock()); // @dbgtodo synchronization - push this up
2378 CordbClass* pClass = pModule->LookupClass(retEvent->EnCUpdate.classMetadataToken);
2379 // if don't find class, that is fine because it hasn't been loaded yet so doesn't
2380 // need to be updated
2381 if (pClass)
2382 {
2383 pClass->MakeOld();
2384 }
2385 }
2386 }
2387 }
2388
2389 LOG((LF_ENC,LL_INFO100, "CordbProcess::ApplyChangesInternal complete.\n"));
2390 }
2391 EX_CATCH_HRESULT(hr);
2392
2393 // process may have gone away by the time we get here so don't assume is there.
2394 CordbProcess *pProcess = GetProcess();
2395 if (pProcess)
2396 {
2397 HRESULT hr2 = pProcess->ReleaseRemoteBuffer(&pRemoteBuf);
2398 TESTANDRETURNHR(hr2);
2399 }
2400 return hr;
2401#else // EnC_SUPPORTED
2402 return E_NOTIMPL;
2403#endif // EnC_SUPPORTED
2404
2405}
2406
2407// Set the JMC status for the entire module.
2408// All methods specified in others[] will have jmc status !fIsUserCode
2409// All other methods will have jmc status fIsUserCode.
2410HRESULT CordbModule::SetJMCStatus(
2411 BOOL fIsUserCode,
2412 ULONG32 cOthers,
2413 mdToken others[])
2414{
2415 PUBLIC_API_ENTRY(this);
2416 FAIL_IF_NEUTERED(this);
2417 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2418
2419 if (m_vmDomainFile.IsNull())
2420 return E_UNEXPECTED;
2421
2422 // @todo -allow the other parameters. These are functions that have default status
2423 // opposite of fIsUserCode.
2424 if (cOthers != 0)
2425 {
2426 _ASSERTE(!"not yet impl for cOthers != 0");
2427 return E_NOTIMPL;
2428 }
2429
2430 // Send event to the LS.
2431 CordbProcess* pProcess = this->GetProcess();
2432 _ASSERTE(pProcess != NULL);
2433
2434
2435 // Tell the LS that this module is/is not user code
2436 DebuggerIPCEvent event;
2437 pProcess->InitIPCEvent(&event, DB_IPCE_SET_MODULE_JMC_STATUS, true, this->GetAppDomain()->GetADToken());
2438 event.SetJMCFunctionStatus.vmDomainFile = m_vmDomainFile;
2439 event.SetJMCFunctionStatus.dwStatus = fIsUserCode;
2440
2441
2442 // Note: two-way event here...
2443 HRESULT hr = pProcess->m_cordb->SendIPCEvent(pProcess, &event, sizeof(DebuggerIPCEvent));
2444
2445 // Stop now if we can't even send the event.
2446 if (!SUCCEEDED(hr))
2447 {
2448 LOG((LF_CORDB, LL_INFO10, "CordbModule::SetJMCStatus failed 0x%08x...\n", hr));
2449
2450 return hr;
2451 }
2452
2453 _ASSERTE(event.type == DB_IPCE_SET_MODULE_JMC_STATUS_RESULT);
2454
2455 LOG((LF_CORDB, LL_INFO10, "returning from CordbModule::SetJMCStatus 0x%08x...\n", hr));
2456
2457 return event.hr;
2458}
2459
2460
2461//
2462// Resolve an assembly given an AssemblyRef token. Note that
2463// this will not trigger the loading of assembly. If assembly is not yet loaded,
2464// this will return an CORDBG_E_CANNOT_RESOLVE_ASSEMBLY error
2465//
2466HRESULT CordbModule::ResolveAssembly(mdToken tkAssemblyRef,
2467 ICorDebugAssembly **ppAssembly)
2468{
2469 PUBLIC_API_ENTRY(this);
2470 FAIL_IF_NEUTERED(this);
2471 ATT_REQUIRE_STOPPED_MAY_FAIL(this->GetProcess());
2472
2473 if(ppAssembly)
2474 {
2475 *ppAssembly = NULL;
2476 }
2477
2478 HRESULT hr = S_OK;
2479 EX_TRY
2480 {
2481 CordbAssembly *pCordbAsm = ResolveAssemblyInternal(tkAssemblyRef);
2482 if (pCordbAsm == NULL)
2483 {
2484 // Don't throw here. It's a common-case failure path and not exceptional.
2485 hr = CORDBG_E_CANNOT_RESOLVE_ASSEMBLY;
2486 }
2487 else if(ppAssembly)
2488 {
2489 _ASSERTE(pCordbAsm != NULL);
2490 *ppAssembly = pCordbAsm;
2491 pCordbAsm->ExternalAddRef();
2492 }
2493 }
2494 EX_CATCH_HRESULT(hr);
2495 return hr;
2496}
2497
2498//---------------------------------------------------------------------------------------
2499// Worker to resolve an assembly ref.
2500//
2501// Arguments:
2502// tkAssemblyRef - token of assembly ref to resolve
2503//
2504// Returns:
2505// Assembly that this token resolves to.
2506// NULL if it's a valid token but the assembly has not yet been resolved.
2507// (This is a non-exceptional error case).
2508//
2509// Notes:
2510// MetaData has tokens to represent a reference to another assembly.
2511// But Loader/Fusion policy ultimately decides which specific assembly is actually loaded
2512// for that token.
2513// This does the lookup of actual assembly and reports back to the debugger.
2514
2515CordbAssembly * CordbModule::ResolveAssemblyInternal(mdToken tkAssemblyRef)
2516{
2517 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
2518
2519 if (TypeFromToken(tkAssemblyRef) != mdtAssemblyRef || tkAssemblyRef == mdAssemblyRefNil)
2520 {
2521 // Not a valid token
2522 ThrowHR(E_INVALIDARG);
2523 }
2524
2525 CordbAssembly * pAssembly = NULL;
2526
2527 if (!m_vmDomainFile.IsNull())
2528 {
2529 // Get DAC to do the real work to resolve the assembly
2530 VMPTR_DomainAssembly vmDomainAssembly = GetProcess()->GetDAC()->ResolveAssembly(m_vmDomainFile, tkAssemblyRef);
2531
2532 // now find the ICorDebugAssembly corresponding to it
2533 if (!vmDomainAssembly.IsNull() && m_pAppDomain != NULL)
2534 {
2535 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
2536 // Don't throw here because if the lookup fails, we want to throw CORDBG_E_CANNOT_RESOLVE_ASSEMBLY.
2537 pAssembly = m_pAppDomain->LookupOrCreateAssembly(vmDomainAssembly);
2538 }
2539 }
2540
2541 return pAssembly;
2542}
2543
2544//
2545// CreateReaderForInMemorySymbols - create an ISymUnmanagedReader object for symbols
2546// which are loaded into memory in the CLR. See interface definition in cordebug.idl for
2547// details.
2548//
2549HRESULT CordbModule::CreateReaderForInMemorySymbols(REFIID riid, void** ppObj)
2550{
2551 PUBLIC_API_ENTRY(this);
2552 FAIL_IF_NEUTERED(this);
2553
2554 CordbProcess *pProcess = GetProcess();
2555 ATT_REQUIRE_STOPPED_MAY_FAIL(pProcess);
2556
2557 HRESULT hr = S_OK;
2558 EX_TRY
2559 {
2560 // Get the symbol memory in a stream to give to the reader.
2561 ReleaseHolder<IStream> pStream;
2562 IDacDbiInterface::SymbolFormat symFormat = GetInMemorySymbolStream(&pStream);
2563
2564 // First create the symbol binder corresponding to the format of the stream
2565 ReleaseHolder<ISymUnmanagedBinder> pBinder;
2566 if (symFormat == IDacDbiInterface::kSymbolFormatPDB)
2567 {
2568#ifndef FEATURE_PAL
2569 // PDB format - use diasymreader.dll with COM activation
2570 InlineSString<_MAX_PATH> ssBuf;
2571 IfFailThrow(GetHModuleDirectory(GetModuleInst(), ssBuf));
2572 IfFailThrow(FakeCoCreateInstanceEx(CLSID_CorSymBinder_SxS,
2573 ssBuf.GetUnicode(),
2574 IID_ISymUnmanagedBinder,
2575 (void**)&pBinder,
2576 NULL));
2577#else
2578 IfFailThrow(FakeCoCreateInstance(CLSID_CorSymBinder_SxS,
2579 IID_ISymUnmanagedBinder,
2580 (void**)&pBinder));
2581#endif
2582 }
2583 else if (symFormat == IDacDbiInterface::kSymbolFormatILDB)
2584 {
2585 // ILDB format - use statically linked-in ildbsymlib
2586 IfFailThrow(IldbSymbolsCreateInstance(CLSID_CorSymBinder_SxS,
2587 IID_ISymUnmanagedBinder,
2588 (void**)&pBinder));
2589 }
2590 else
2591 {
2592 // No in-memory symbols, return the appropriate error
2593 _ASSERTE(symFormat == IDacDbiInterface::kSymbolFormatNone);
2594 if (m_fDynamic || m_fInMemory)
2595 {
2596 // This is indeed an in-memory or dynamic module, we just don't have any symbols for it.
2597 // This means the application didn't supply any, or they are not yet available. Symbols
2598 // first become available at LoadClass time for dynamic modules and UpdateModuleSymbols
2599 // time for non-dynamic in-memory modules.
2600 ThrowHR(CORDBG_E_SYMBOLS_NOT_AVAILABLE);
2601 }
2602
2603 // This module is on disk - the debugger should use it's normal symbol-loading logic.
2604 ThrowHR(CORDBG_E_MODULE_LOADED_FROM_DISK);
2605 }
2606
2607 // In the attach or dump case, if we attach or take the dump after we have defined a dynamic module, we may
2608 // have already set the symbol format to "PDB" by the time we call CreateReaderForInMemorySymbols during initialization
2609 // for loaded modules. (In the launch case, we do this initialization when the module is actually loaded, and before we
2610 // set the symbol format.) When we call CreateReaderForInMemorySymbols, we can't assume the initialization was already
2611 // performed or specifically, that we already have m_pIMImport initialized. We can't call into diasymreader with a NULL
2612 // pointer as the value for m_pIMImport, so we need to check that here.
2613 if (m_pIMImport == NULL)
2614 {
2615 ThrowHR(CORDBG_E_SYMBOLS_NOT_AVAILABLE);
2616 }
2617
2618 // Now create the symbol reader from the data
2619 ReleaseHolder<ISymUnmanagedReader> pReader;
2620 IfFailThrow(pBinder->GetReaderFromStream(m_pIMImport, pStream, &pReader));
2621
2622 // Attempt to return the interface requested
2623 // Note that this does an AddRef for our return value ppObj, so we don't suppress the release
2624 // of the pReader holder.
2625 IfFailThrow(pReader->QueryInterface(riid, ppObj));
2626 }
2627 EX_CATCH_HRESULT(hr);
2628 return hr;
2629}
2630
2631/* ------------------------------------------------------------------------- *
2632 * Class class
2633 * ------------------------------------------------------------------------- */
2634
2635//---------------------------------------------------------------------------------------
2636// Set the continue counter that marks when the module is in its Load event
2637//
2638// Notes:
2639// Jit flags can only be changed in the real module Load event. We may
2640// have multiple module load events on different threads coming at the
2641// same time. So each module load tracks its continue counter.
2642//
2643// This can be used by code:CordbModule::EnsureModuleIsInLoadCallback to
2644// properly return CORDBG_E_MUST_BE_IN_LOAD_MODULE
2645void CordbModule::SetLoadEventContinueMarker()
2646{
2647 // Well behaved targets should only set this once.
2648 GetProcess()->TargetConsistencyCheck(m_nLoadEventContinueCounter == 0);
2649
2650 m_nLoadEventContinueCounter = GetProcess()->m_continueCounter;
2651}
2652
2653//---------------------------------------------------------------------------------------
2654// Return CORDBG_E_MUST_BE_IN_LOAD_MODULE if the module is not in the load module callback.
2655//
2656// Notes:
2657// The comparison is done via continue counters. The counter of the load
2658// event is cached via code:CordbModule::SetLoadEventContinueMarker.
2659//
2660// This state is currently stored on the RS. Alternatively, it could likely be retreived from the LS state as
2661// well. One disadvantage of the current model is that if we detach during the load-module callback and
2662// then reattach, the RS state is flushed and we lose the fact that we can toggle the jit flags.
2663HRESULT CordbModule::EnsureModuleIsInLoadCallback()
2664{
2665 if (this->m_nLoadEventContinueCounter < GetProcess()->m_continueCounter)
2666 {
2667 return CORDBG_E_MUST_BE_IN_LOAD_MODULE;
2668 }
2669 else
2670 {
2671 return S_OK;
2672 }
2673}
2674
2675// Implementation of ICorDebugModule2::SetJITCompilerFlags
2676// See also code:CordbModule::EnableJITDebugging
2677HRESULT CordbModule::SetJITCompilerFlags(DWORD dwFlags)
2678{
2679 PUBLIC_REENTRANT_API_ENTRY(this);
2680 FAIL_IF_NEUTERED(this);
2681
2682 CordbProcess *pProcess = GetProcess();
2683
2684 ATT_REQUIRE_STOPPED_MAY_FAIL(pProcess);
2685 HRESULT hr = S_OK;
2686
2687 EX_TRY
2688 {
2689 // can't have a subset of these, eg 0x101, so make sure we have an exact match
2690 if ((dwFlags != CORDEBUG_JIT_DEFAULT) &&
2691 (dwFlags != CORDEBUG_JIT_DISABLE_OPTIMIZATION) &&
2692 (dwFlags != CORDEBUG_JIT_ENABLE_ENC))
2693 {
2694 hr = E_INVALIDARG;
2695 }
2696 else
2697 {
2698 BOOL fAllowJitOpts = ((dwFlags & CORDEBUG_JIT_DISABLE_OPTIMIZATION) != CORDEBUG_JIT_DISABLE_OPTIMIZATION);
2699 BOOL fEnableEnC = ((dwFlags & CORDEBUG_JIT_ENABLE_ENC) == CORDEBUG_JIT_ENABLE_ENC);
2700
2701 // Can only change jit flags when module is first loaded and before there's any jitted code.
2702 // This ensures all code in the module is jitted the same way.
2703 hr = EnsureModuleIsInLoadCallback();
2704
2705 if (SUCCEEDED(hr))
2706 {
2707 // DD interface will check if it's a valid time to change the flags.
2708 hr = pProcess->GetDAC()->SetCompilerFlags(GetRuntimeDomainFile(), fAllowJitOpts, fEnableEnC);
2709 }
2710 }
2711 }
2712 EX_CATCH_HRESULT(hr);
2713
2714 // emulate v2 hresults
2715 if (GetProcess()->GetShim() != NULL)
2716 {
2717 // Emulate Whidbey error hresults
2718 hr = GetProcess()->GetShim()->FilterSetJitFlagsHresult(hr);
2719 }
2720 return hr;
2721
2722}
2723
2724// Implementation of ICorDebugModule2::GetJitCompilerFlags
2725HRESULT CordbModule::GetJITCompilerFlags(DWORD *pdwFlags )
2726{
2727 PUBLIC_REENTRANT_API_ENTRY(this);
2728 FAIL_IF_NEUTERED(this);
2729 VALIDATE_POINTER_TO_OBJECT(pdwFlags, DWORD*);
2730 *pdwFlags = CORDEBUG_JIT_DEFAULT;;
2731
2732 CordbProcess *pProcess = GetProcess();
2733
2734
2735 ATT_REQUIRE_STOPPED_MAY_FAIL(pProcess);
2736 HRESULT hr = S_OK;
2737
2738 EX_TRY
2739 {
2740 BOOL fAllowJitOpts;
2741 BOOL fEnableEnC;
2742
2743 pProcess->GetDAC()->GetCompilerFlags (
2744 GetRuntimeDomainFile(),
2745 &fAllowJitOpts,
2746 &fEnableEnC);
2747
2748 if (fEnableEnC)
2749 {
2750 *pdwFlags = CORDEBUG_JIT_ENABLE_ENC;
2751 }
2752 else if (! fAllowJitOpts)
2753 {
2754 *pdwFlags = CORDEBUG_JIT_DISABLE_OPTIMIZATION;
2755 }
2756
2757 }
2758 EX_CATCH_HRESULT(hr);
2759 return hr;
2760}
2761
2762BOOL CordbModule::IsWinMD()
2763{
2764 CONTRACTL
2765 {
2766 THROWS;
2767 }
2768 CONTRACTL_END;
2769
2770 if (m_isIlWinMD == Uninitialized)
2771 {
2772 BOOL isWinRT;
2773 HRESULT hr = E_FAIL;
2774
2775 {
2776 RSLockHolder processLockHolder(GetProcess()->GetProcessLock());
2777 hr = GetProcess()->GetDAC()->IsWinRTModule(m_vmModule, isWinRT);
2778 }
2779
2780 _ASSERTE(SUCCEEDED(hr));
2781 if (FAILED(hr))
2782 ThrowHR(hr);
2783
2784 if (isWinRT)
2785 m_isIlWinMD = True;
2786 else
2787 m_isIlWinMD = False;
2788 }
2789
2790 return m_isIlWinMD == True;
2791}
2792
2793/* ------------------------------------------------------------------------- *
2794 * CordbCode class
2795 * ------------------------------------------------------------------------- */
2796//-----------------------------------------------------------------------------
2797// CordbCode constructor
2798// Arguments:
2799// Input:
2800// pFunction - CordbFunction instance for this function
2801// encVersion - Edit and Continue version number for this code chunk
2802// fIsIL - indicates whether the instance is a CordbILCode (as
2803// opposed to a CordbNativeCode)
2804// id - This is the hashtable key for CordbCode objects
2805// - for native code, the code start address
2806// - for IL code, 0
2807// - for ReJit IL code, the remote pointer to the ReJitSharedInfo
2808// Output:
2809// fields of the CordbCode instance have been initialized
2810//-----------------------------------------------------------------------------
2811
2812CordbCode::CordbCode(CordbFunction * pFunction, UINT_PTR id, SIZE_T encVersion, BOOL fIsIL)
2813 : CordbBase(pFunction->GetProcess(), id, enumCordbCode),
2814 m_fIsIL(fIsIL),
2815 m_nVersion(encVersion),
2816 m_rgbCode(NULL),
2817 m_continueCounterLastSync(0),
2818 m_pFunction(pFunction)
2819{
2820 _ASSERTE(pFunction != NULL);
2821 _ASSERTE(m_nVersion >= CorDB_DEFAULT_ENC_FUNCTION_VERSION);
2822} // CordbCode::CordbCode
2823
2824//-----------------------------------------------------------------------------
2825// Destructor for CordbCode object
2826//-----------------------------------------------------------------------------
2827CordbCode::~CordbCode()
2828{
2829 _ASSERTE(IsNeutered());
2830}
2831
2832//-----------------------------------------------------------------------------
2833// Neutered by CordbFunction
2834// See CordbBase::Neuter for neuter semantics.
2835//-----------------------------------------------------------------------------
2836void CordbCode::Neuter()
2837{
2838 m_pFunction = NULL;
2839
2840 delete [] m_rgbCode;
2841 m_rgbCode = NULL;
2842
2843 CordbBase::Neuter();
2844}
2845
2846//-----------------------------------------------------------------------------
2847// Public method for IUnknown::QueryInterface.
2848// Has standard QI semantics.
2849//-----------------------------------------------------------------------------
2850HRESULT CordbCode::QueryInterface(REFIID id, void ** pInterface)
2851{
2852 if (id == IID_ICorDebugCode)
2853 {
2854 *pInterface = static_cast<ICorDebugCode*>(this);
2855 }
2856 else if (id == IID_IUnknown)
2857 {
2858 *pInterface = static_cast<IUnknown *>(static_cast<ICorDebugCode *>(this));
2859 }
2860 else
2861 {
2862 *pInterface = NULL;
2863 return E_NOINTERFACE;
2864 }
2865
2866 ExternalAddRef();
2867 return S_OK;
2868}
2869
2870//-----------------------------------------------------------------------------
2871// NOT IMPLEMENTED. Remap sequence points are entirely private to the LS,
2872// and ICorDebug will dispatch a RemapOpportunity callback to notify the
2873// debugger instead of letting the debugger query for the points.
2874//
2875// Returns: E_NOTIMPL
2876//-----------------------------------------------------------------------------
2877HRESULT CordbCode::GetEnCRemapSequencePoints(ULONG32 cMap, ULONG32 * pcMap, ULONG32 offsets[])
2878{
2879 FAIL_IF_NEUTERED(this);
2880 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcMap, ULONG32*);
2881 VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(offsets, ULONG32*, cMap, true, true);
2882
2883 //
2884 // Old EnC interface - deprecated
2885 //
2886 return E_NOTIMPL;
2887} // CordbCode::GetEnCRemapSequencePoints
2888
2889
2890//-----------------------------------------------------------------------------
2891// CordbCode::IsIL
2892// Public method to determine if this Code object represents IL or native code.
2893//
2894// Parameters:
2895// pbIL - OUT: on return, set to True if IL code, else False.
2896//
2897// Returns:
2898// S_OK on success.
2899//-----------------------------------------------------------------------------
2900HRESULT CordbCode::IsIL(BOOL *pbIL)
2901{
2902 PUBLIC_API_ENTRY(this);
2903 FAIL_IF_NEUTERED(this);
2904 VALIDATE_POINTER_TO_OBJECT(pbIL, BOOL *);
2905
2906 *pbIL = IsIL();
2907
2908 return S_OK;
2909}
2910
2911//-----------------------------------------------------------------------------
2912// CordbCode::GetFunction
2913// Public method to get the Function object associated with this Code object.
2914// Function:Code = 1:1 for IL, and 1:n for Native. So there is always a single
2915// unique Function object to return.
2916//
2917// Parameters:
2918// ppFunction - OUT: returns the Function object for this Code.
2919//
2920// Returns:
2921// S_OK - on success.
2922//-----------------------------------------------------------------------------
2923HRESULT CordbCode::GetFunction(ICorDebugFunction **ppFunction)
2924{
2925 PUBLIC_API_ENTRY(this);
2926 FAIL_IF_NEUTERED(this);
2927 VALIDATE_POINTER_TO_OBJECT(ppFunction, ICorDebugFunction **);
2928
2929 *ppFunction = static_cast<ICorDebugFunction*> (m_pFunction);
2930 m_pFunction->ExternalAddRef();
2931
2932 return S_OK;
2933}
2934
2935//-----------------------------------------------------------------------------
2936// CordbCode::GetSize
2937// Get the size of the code in bytes. If this is IL code, it will be bytes of IL.
2938// If this is native code, it will be bytes of native code.
2939//
2940// Parameters:
2941// pcBytes - OUT: on return, set to the size of the code in bytes.
2942//
2943// Returns:
2944// S_OK on success.
2945//-----------------------------------------------------------------------------
2946HRESULT CordbCode::GetSize(ULONG32 *pcBytes)
2947{
2948 PUBLIC_REENTRANT_API_ENTRY(this);
2949 FAIL_IF_NEUTERED(this);
2950 VALIDATE_POINTER_TO_OBJECT(pcBytes, ULONG32 *);
2951
2952 *pcBytes = GetSize();
2953 return S_OK;
2954}
2955
2956//-----------------------------------------------------------------------------
2957// CordbCode::CreateBreakpoint
2958// public method to create a breakpoint in the code.
2959//
2960// Parameters:
2961// offset - offset in bytes to set the breakpoint at. If this is a Native
2962// code object (IsIl == false), then units are bytes of native code. If
2963// this is an IL code object, then units are bytes of IL code.
2964// ppBreakpoint- out-parameter to hold newly created breakpoint object.
2965//
2966// Return value:
2967// S_OK iff *ppBreakpoint is set. Else some error.
2968//-----------------------------------------------------------------------------
2969HRESULT CordbCode::CreateBreakpoint(ULONG32 offset,
2970 ICorDebugFunctionBreakpoint **ppBreakpoint)
2971{
2972 PUBLIC_REENTRANT_API_ENTRY(this);
2973 FAIL_IF_NEUTERED(this);
2974 VALIDATE_POINTER_TO_OBJECT(ppBreakpoint, ICorDebugFunctionBreakpoint **);
2975
2976 HRESULT hr;
2977 ULONG32 size = GetSize();
2978 BOOL offsetIsIl = IsIL();
2979 LOG((LF_CORDB, LL_INFO10000, "CCode::CreateBreakpoint, offset=%d, size=%d, IsIl=%d, this=0x%p\n",
2980 offset, size, offsetIsIl, this));
2981
2982 // Make sure the offset is within range of the method.
2983 // If we're native code, then both offset & total code size are bytes of native code,
2984 // else they're both bytes of IL.
2985 if (offset >= size)
2986 {
2987 return CORDBG_E_UNABLE_TO_SET_BREAKPOINT;
2988 }
2989
2990 CordbFunctionBreakpoint *bp = new (nothrow) CordbFunctionBreakpoint(this, offset, offsetIsIl);
2991
2992 if (bp == NULL)
2993 return E_OUTOFMEMORY;
2994
2995 hr = bp->Activate(TRUE);
2996 if (SUCCEEDED(hr))
2997 {
2998 *ppBreakpoint = static_cast<ICorDebugFunctionBreakpoint*> (bp);
2999 bp->ExternalAddRef();
3000 return S_OK;
3001 }
3002 else
3003 {
3004 delete bp;
3005 return hr;
3006 }
3007}
3008
3009//-----------------------------------------------------------------------------
3010// CordbCode::GetCode
3011// Public method to get the code-bytes for this Code object. For an IL-code
3012// object, this will be bytes of IL. For a native-code object, this will be
3013// bytes of native opcodes.
3014// The units of the offsets are the same as the units on the CordbCode object.
3015// (eg, IL offsets for an IL code object, and native offsets for a native code object)
3016// This will glue together hot + cold regions into a single blob.
3017//
3018// Units are also logical (aka linear) values, which
3019// Parameters:
3020// startOffset - linear offset in Code to start copying from.
3021// endOffset - linear offset in Code to end copying from. Total bytes copied would be (endOffset - startOffset)
3022// cBufferAlloc - number of bytes in the buffer supplied by the buffer[] parameter.
3023// buffer - caller allocated storage to copy bytes into.
3024// pcBufferSize - required out-parameter, holds number of bytes copied into buffer.
3025//
3026// Returns:
3027// S_OK if copy successful. Else error.
3028//-----------------------------------------------------------------------------
3029HRESULT CordbCode::GetCode(ULONG32 startOffset,
3030 ULONG32 endOffset,
3031 ULONG32 cBufferAlloc,
3032 BYTE buffer[],
3033 ULONG32 *pcBufferSize)
3034{
3035 PUBLIC_REENTRANT_API_ENTRY(this);
3036 FAIL_IF_NEUTERED(this);
3037 VALIDATE_POINTER_TO_OBJECT_ARRAY(buffer, BYTE, cBufferAlloc, true, true);
3038 VALIDATE_POINTER_TO_OBJECT(pcBufferSize, ULONG32 *);
3039
3040 LOG((LF_CORDB,LL_EVERYTHING, "CC::GC: for token:0x%x\n", m_pFunction->GetMetadataToken()));
3041
3042 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3043
3044 HRESULT hr = S_OK;
3045 *pcBufferSize = 0;
3046
3047 // Check ranges.
3048 ULONG32 totalSize = GetSize();
3049
3050 if (cBufferAlloc < endOffset - startOffset)
3051 endOffset = startOffset + cBufferAlloc;
3052
3053 if (endOffset > totalSize)
3054 endOffset = totalSize;
3055
3056 if (startOffset > totalSize)
3057 startOffset = totalSize;
3058
3059 // Check the continue counter since WriteMemory bumps it up.
3060 if ((m_rgbCode == NULL) ||
3061 (m_continueCounterLastSync < GetProcess()->m_continueCounter))
3062 {
3063 ReadCodeBytes();
3064 m_continueCounterLastSync = GetProcess()->m_continueCounter;
3065 }
3066
3067 // if we just got the code, we'll have to copy it over
3068 if (*pcBufferSize == 0 && m_rgbCode != NULL)
3069 {
3070 memcpy(buffer,
3071 m_rgbCode+startOffset,
3072 endOffset - startOffset);
3073 *pcBufferSize = endOffset - startOffset;
3074 }
3075 return hr;
3076
3077} // CordbCode::GetCode
3078
3079#include "dbgipcevents.h"
3080
3081//-----------------------------------------------------------------------------
3082// CordbCode::GetVersionNumber
3083// Public method to get the EnC version number of the code.
3084//
3085// Parameters:
3086// nVersion - OUT: on return, set to the version number.
3087//
3088// Returns:
3089// S_OK on success.
3090//-----------------------------------------------------------------------------
3091HRESULT CordbCode::GetVersionNumber( ULONG32 *nVersion)
3092{
3093 PUBLIC_API_ENTRY(this);
3094 FAIL_IF_NEUTERED(this);
3095 VALIDATE_POINTER_TO_OBJECT(nVersion, ULONG32 *);
3096
3097 LOG((LF_CORDB,LL_INFO10000,"R:CC:GVN:Returning 0x%x "
3098 "as version\n",m_nVersion));
3099
3100 *nVersion = (ULONG32)m_nVersion;
3101
3102#ifndef EnC_SUPPORTED
3103 _ASSERTE(*nVersion == 1);
3104#endif // EnC_SUPPORTED
3105
3106 return S_OK;
3107}
3108
3109// get the CordbFunction instance for this code object
3110CordbFunction * CordbCode::GetFunction()
3111{
3112 _ASSERTE(m_pFunction != NULL);
3113 return m_pFunction;
3114}
3115
3116/* ------------------------------------------------------------------------- *
3117 * CordbILCode class
3118 * ------------------------------------------------------------------------- */
3119
3120//-----------------------------------------------------------------------------
3121// CordbILCode ctor to make IL code.
3122// Arguments:
3123// Input:
3124// pFunction - pointer to the CordbFunction instance for this function
3125// codeRegionInfo - starting address and size in bytes of IL code blob
3126// nVersion - EnC version number for this IL code blob
3127// localVarSigToken - LocalVarSig for this IL blob
3128// id - the key when using ILCode in a CordbHashTable
3129// Output:
3130// fields of this instance of CordbILCode have been initialized
3131//-----------------------------------------------------------------------------
3132CordbILCode::CordbILCode(CordbFunction * pFunction,
3133 TargetBuffer codeRegionInfo,
3134 SIZE_T nVersion,
3135 mdSignature localVarSigToken,
3136 UINT_PTR id)
3137 : CordbCode(pFunction, id, nVersion, TRUE),
3138#ifdef EnC_SUPPORTED
3139 m_fIsOld(FALSE),
3140#endif
3141 m_codeRegionInfo(codeRegionInfo),
3142 m_localVarSigToken(localVarSigToken)
3143{
3144} // CordbILCode::CordbILCode
3145
3146
3147#ifdef EnC_SUPPORTED
3148//-----------------------------------------------------------------------------
3149// CordbILCode::MakeOld
3150// Internal method to perform any cleanup necessary when a code blob is no longer
3151// the most current.
3152//-----------------------------------------------------------------------------
3153void CordbILCode::MakeOld()
3154{
3155 m_fIsOld = TRUE;
3156}
3157#endif
3158
3159//-----------------------------------------------------------------------------
3160// CordbILCode::GetAddress
3161// Public method to get the Entry address for the code. This is the address
3162// where the method first starts executing.
3163//
3164// Parameters:
3165// pStart - out-parameter to hold start address.
3166//
3167// Returns:
3168// S_OK if *pStart is properly updated.
3169//-----------------------------------------------------------------------------
3170HRESULT CordbILCode::GetAddress(CORDB_ADDRESS * pStart)
3171{
3172 PUBLIC_REENTRANT_API_ENTRY(this);
3173 FAIL_IF_NEUTERED(this);
3174 VALIDATE_POINTER_TO_OBJECT(pStart, CORDB_ADDRESS *);
3175
3176
3177 _ASSERTE(this != NULL);
3178 _ASSERTE(this->GetFunction() != NULL);
3179 _ASSERTE(this->GetFunction()->GetModule() != NULL);
3180 _ASSERTE(this->GetFunction()->GetModule()->GetProcess() == GetProcess());
3181
3182 *pStart = (m_codeRegionInfo.pAddress);
3183
3184 return S_OK;
3185} // CordbILCode::GetAddress
3186
3187//-----------------------------------------------------------------------------
3188// CordbILCode::ReadCodeBytes
3189// Reads the actual bytes of IL code into the data member m_rgbCode
3190// Arguments:
3191// none (uses data members)
3192// Return value:
3193// standard HRESULT values
3194// also allocates and initializes m_rgbCode
3195// Notes: assumes that the caller has checked to ensure that m_rgbCode doesn't
3196// hold valid data
3197//-----------------------------------------------------------------------------
3198HRESULT CordbILCode::ReadCodeBytes()
3199{
3200 HRESULT hr = S_OK;
3201 EX_TRY
3202 {
3203 // We have an address & size, so we'll just call ReadMemory.
3204 // This will conveniently strip out any patches too.
3205 CORDB_ADDRESS pStart = m_codeRegionInfo.pAddress;
3206 ULONG32 cbSize = (ULONG32) m_codeRegionInfo.cbSize;
3207
3208 delete [] m_rgbCode;
3209 m_rgbCode = new BYTE[cbSize]; // throws
3210
3211 SIZE_T cbRead;
3212 hr = GetProcess()->ReadMemory(pStart, cbSize, m_rgbCode, &cbRead);
3213 IfFailThrow(hr);
3214
3215 SIMPLIFYING_ASSUMPTION(cbRead == cbSize);
3216 }
3217 EX_CATCH_HRESULT(hr);
3218 return hr;
3219} // CordbILCode::ReadCodeBytes
3220
3221//-----------------------------------------------------------------------------
3222// CordbILCode::GetILToNativeMapping
3223// Public method (implements ICorDebugCode) to get the IL-->{ Native Start, Native End} mapping.
3224// Since 1 CordbILCode can map to multiple CordbNativeCode due to generics, we cannot reliably return the
3225// mapping information in all cases. So we always fail with CORDBG_E_NON_NATIVE_FRAME. The caller should
3226// call code:CordbNativeCode::GetILToNativeMapping instead.
3227//
3228// Parameters:
3229// cMap - size of incoming map[] array (in elements).
3230// pcMap - OUT: full size of IL-->Native map (in elements).
3231// map - caller allocated array to be filled in.
3232//
3233// Returns:
3234// CORDBG_E_NON_NATIVE_FRAME in all cases
3235//-----------------------------------------------------------------------------
3236HRESULT CordbILCode::GetILToNativeMapping(ULONG32 cMap,
3237 ULONG32 * pcMap,
3238 COR_DEBUG_IL_TO_NATIVE_MAP map[])
3239{
3240 PUBLIC_API_ENTRY(this);
3241 FAIL_IF_NEUTERED(this);
3242 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcMap, ULONG32 *);
3243 VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(map, COR_DEBUG_IL_TO_NATIVE_MAP *, cMap, true, true);
3244
3245 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3246
3247 return CORDBG_E_NON_NATIVE_FRAME;
3248} // CordbILCode::GetILToNativeMapping
3249
3250
3251/*
3252* CordbILCode::GetLocalVarSig
3253*
3254* Get the method's local variable metadata signature. This may be cached, but for dynamic modules we'll always
3255* read it from the metadata. This function also returns the count of local variables in the method.
3256*
3257* Parameters:
3258* pLocalSigParser - OUT: the local variable signature for the method.
3259* pLocalCount - OUT: the number of locals the method has.
3260*
3261* Returns:
3262* HRESULT for success or failure.
3263*
3264*/
3265HRESULT CordbILCode::GetLocalVarSig(SigParser *pLocalSigParser,
3266 ULONG *pLocalVarCount)
3267{
3268 INTERNAL_SYNC_API_ENTRY(GetProcess());
3269
3270 CONTRACTL // @dbgtodo exceptions - convert to throws...
3271 {
3272 NOTHROW;
3273 }
3274 CONTRACTL_END;
3275
3276 FAIL_IF_NEUTERED(this);
3277 HRESULT hr = S_OK;
3278
3279 // A function will not have a local var sig if it has no locals!
3280 if (m_localVarSigToken != mdSignatureNil)
3281 {
3282 PCCOR_SIGNATURE localSignature;
3283 ULONG size;
3284 ULONG localCount;
3285
3286 EX_TRY // // @dbgtodo exceptions - push this up
3287 {
3288 GetFunction()->GetModule()->UpdateMetaDataCacheIfNeeded(m_localVarSigToken);
3289 hr = GetFunction()->GetModule()->GetMetaDataImporter()->GetSigFromToken(m_localVarSigToken,
3290 &localSignature,
3291 &size);
3292 }
3293 EX_CATCH_HRESULT(hr);
3294 if (FAILED(hr))
3295 {
3296 LOG((LF_CORDB, LL_WARNING, "CICF::GLVS caught hr=0x%x\n", hr));
3297 }
3298 IfFailRet(hr);
3299
3300 LOG((LF_CORDB, LL_INFO100000, "CIC::GLVS creating sig parser sig=0x%x size=0x%x\n", localSignature, size));
3301 SigParser sigParser = SigParser(localSignature, size);
3302
3303 ULONG data;
3304
3305 IfFailRet(sigParser.GetCallingConvInfo(&data));
3306
3307 _ASSERTE(data == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG);
3308
3309 // Snagg the count of locals in the sig.
3310 IfFailRet(sigParser.GetData(&localCount));
3311 LOG((LF_CORDB, LL_INFO100000, "CIC::GLVS localCount=0x%x\n", localCount));
3312 if (pLocalSigParser != NULL)
3313 {
3314 *pLocalSigParser = sigParser;
3315 }
3316 if (pLocalVarCount != NULL)
3317 {
3318 *pLocalVarCount = localCount;
3319 }
3320 }
3321 else
3322 {
3323 //
3324 // Signature is Nil, so fill in everything with NULLs and zeros
3325 //
3326 if (pLocalSigParser != NULL)
3327 {
3328 *pLocalSigParser = SigParser(NULL, 0);
3329 }
3330
3331 if (pLocalVarCount != NULL)
3332 {
3333 *pLocalVarCount = 0;
3334 }
3335 }
3336 LOG((LF_CORDB, LL_INFO100000, "CIC::GLVS returning hr=0x%x\n", hr));
3337 return hr;
3338}
3339
3340//-----------------------------------------------------------------------------
3341// CordbILCode::GetLocalVariableType
3342// Internal method. Return the type of an IL local, specified by 0-based index.
3343//
3344// Parameters:
3345// dwIndex - 0-based index for IL local number.
3346// inst - instantiation information if this is a generic function. Eg,
3347// if function is List<T>, inst describes T.
3348// res - out parameter, yields to CordbType of the local.
3349//
3350// Return:
3351// S_OK on success.
3352//
3353HRESULT CordbILCode::GetLocalVariableType(DWORD dwIndex,
3354 const Instantiation * pInst,
3355 CordbType ** ppResultType)
3356{
3357 ATT_ALLOW_LIVE_DO_STOPGO(GetProcess());
3358 LOG((LF_CORDB, LL_INFO10000, "CIC::GLVT dwIndex=0x%x pInst=0x%p\n", dwIndex, pInst));
3359 HRESULT hr = S_OK;
3360
3361 EX_TRY
3362 {
3363 // Get the local variable signature.
3364 SigParser sigParser;
3365 ULONG cLocals;
3366
3367 IfFailThrow(GetLocalVarSig(&sigParser, &cLocals));
3368
3369 // Check the index.
3370 if (dwIndex >= cLocals)
3371 {
3372 ThrowHR(E_INVALIDARG);
3373 }
3374
3375 // Run the signature and find the required argument.
3376 for (unsigned int i = 0; i < dwIndex; i++)
3377 {
3378 LOG((LF_CORDB, LL_INFO10000, "CIC::GLVT scanning index 0x%x\n", dwIndex));
3379 IfFailThrow(sigParser.SkipExactlyOne());
3380 }
3381
3382 hr = CordbType::SigToType(GetFunction()->GetModule(), &sigParser, pInst, ppResultType);
3383 LOG((LF_CORDB, LL_INFO10000, "CIC::GLVT CT::SigToType returned hr=0x%x\n", hr));
3384 IfFailThrow(hr);
3385
3386 } EX_CATCH_HRESULT(hr);
3387 return hr;
3388}
3389
3390mdSignature CordbILCode::GetLocalVarSigToken()
3391{
3392 return m_localVarSigToken;
3393}
3394
3395HRESULT CordbILCode::CreateNativeBreakpoint(ICorDebugFunctionBreakpoint **ppBreakpoint)
3396{
3397 FAIL_IF_NEUTERED(this);
3398 VALIDATE_POINTER_TO_OBJECT(ppBreakpoint, ICorDebugFunctionBreakpoint **);
3399
3400 HRESULT hr;
3401 ULONG32 size = GetSize();
3402 LOG((LF_CORDB, LL_INFO10000, "CordbILCode::CreateNativeBreakpoint, size=%d, this=0x%p\n",
3403 size, this));
3404
3405 ULONG32 offset = 0;
3406 CordbFunctionBreakpoint *bp = new (nothrow) CordbFunctionBreakpoint(this, offset, FALSE);
3407
3408 if (bp == NULL)
3409 {
3410 return E_OUTOFMEMORY;
3411 }
3412
3413 hr = bp->Activate(TRUE);
3414 if (SUCCEEDED(hr))
3415 {
3416 *ppBreakpoint = static_cast<ICorDebugFunctionBreakpoint*> (bp);
3417 bp->ExternalAddRef();
3418 return S_OK;
3419 }
3420 else
3421 {
3422 delete bp;
3423 return hr;
3424 }
3425}
3426
3427
3428
3429CordbReJitILCode::CordbReJitILCode(CordbFunction *pFunction, SIZE_T encVersion, VMPTR_ILCodeVersionNode vmILCodeVersionNode) :
3430CordbILCode(pFunction, TargetBuffer(), encVersion, mdSignatureNil, VmPtrToCookie(vmILCodeVersionNode)),
3431m_cClauses(0),
3432m_cbLocalIL(0),
3433m_cILMap(0)
3434{
3435 _ASSERTE(!vmILCodeVersionNode.IsNull());
3436 DacSharedReJitInfo data = { 0 };
3437 IfFailThrow(GetProcess()->GetDAC()->GetILCodeVersionNodeData(vmILCodeVersionNode, &data));
3438 IfFailThrow(Init(&data));
3439}
3440
3441//-----------------------------------------------------------------------------
3442// CordbReJitILCode::Init
3443//
3444// Returns:
3445// S_OK if all fields are inited. Else error.
3446HRESULT CordbReJitILCode::Init(DacSharedReJitInfo* pSharedReJitInfo)
3447{
3448 HRESULT hr = S_OK;
3449
3450 // Instrumented IL map
3451 if (pSharedReJitInfo->m_cInstrumentedMapEntries)
3452 {
3453 if (pSharedReJitInfo->m_cInstrumentedMapEntries > 100000)
3454 return CORDBG_E_TARGET_INCONSISTENT;
3455 m_cILMap = pSharedReJitInfo->m_cInstrumentedMapEntries;
3456 m_pILMap = new (nothrow)COR_IL_MAP[m_cILMap];
3457 TargetBuffer mapBuffer(pSharedReJitInfo->m_rgInstrumentedMapEntries, m_cILMap*sizeof(COR_IL_MAP));
3458 IfFailRet(GetProcess()->SafeReadBuffer(mapBuffer, (BYTE*)m_pILMap.GetValue(), FALSE /* bThrowOnError */));
3459 }
3460
3461 // Read the method's IL header
3462 CORDB_ADDRESS pIlHeader = pSharedReJitInfo->m_pbIL;
3463 IMAGE_COR_ILMETHOD_FAT header = { 0 };
3464 bool headerMustBeTiny = false;
3465 ULONG32 headerSize = 0;
3466 hr = GetProcess()->SafeReadStruct(pIlHeader, &header);
3467 if (hr != S_OK)
3468 {
3469 // Its possible the header is tiny and there isn't enough memory to read a complete
3470 // FAT header
3471 headerMustBeTiny = true;
3472 IfFailRet(GetProcess()->SafeReadStruct(pIlHeader, (IMAGE_COR_ILMETHOD_TINY *)&header));
3473 }
3474
3475 // Read the ILCodeSize and LocalVarSigTok from header
3476 ULONG32 ilCodeSize = 0;
3477 IMAGE_COR_ILMETHOD_TINY *pMethodTinyHeader = (IMAGE_COR_ILMETHOD_TINY *)&header;
3478 bool isTinyHeader = ((pMethodTinyHeader->Flags_CodeSize & (CorILMethod_FormatMask >> 1)) == CorILMethod_TinyFormat);
3479 if (isTinyHeader)
3480 {
3481 ilCodeSize = (((unsigned)pMethodTinyHeader->Flags_CodeSize) >> (CorILMethod_FormatShift - 1));
3482 headerSize = sizeof(IMAGE_COR_ILMETHOD_TINY);
3483 m_localVarSigToken = mdSignatureNil;
3484 }
3485 else if (headerMustBeTiny)
3486 {
3487 // header was not CorILMethod_TinyFormat
3488 // this is not possible, must be an error when reading from data target
3489 return CORDBG_E_READVIRTUAL_FAILURE;
3490 }
3491 else
3492 {
3493 ilCodeSize = header.CodeSize;
3494 headerSize = header.Size * 4;
3495 m_localVarSigToken = header.LocalVarSigTok;
3496 }
3497 if (ilCodeSize == 0 || ilCodeSize > 100000)
3498 {
3499 return CORDBG_E_TARGET_INCONSISTENT;
3500 }
3501
3502 m_codeRegionInfo.Init(pIlHeader + headerSize, ilCodeSize);
3503 m_pLocalIL = new (nothrow) BYTE[ilCodeSize];
3504 if (m_pLocalIL == NULL)
3505 return E_OUTOFMEMORY;
3506 m_cbLocalIL = ilCodeSize;
3507 IfFailRet(GetProcess()->SafeReadBuffer(m_codeRegionInfo, m_pLocalIL, FALSE /*throwOnError*/));
3508
3509 // Check if this il code has exception clauses
3510 if ((pMethodTinyHeader->Flags_CodeSize & CorILMethod_MoreSects) == 0)
3511 {
3512 return S_OK; // no EH, done initing
3513 }
3514
3515 // EH section starts at the 4 byte aligned address after the code
3516 CORDB_ADDRESS ehClauseHeader = ((pIlHeader + headerSize + ilCodeSize - 1) & ~3) + 4;
3517 BYTE kind = 0;
3518 IfFailRet(GetProcess()->SafeReadStruct(ehClauseHeader, &kind));
3519 if ((kind & CorILMethod_Sect_KindMask) != CorILMethod_Sect_EHTable)
3520 {
3521 return S_OK;
3522 }
3523 if (kind & CorILMethod_Sect_FatFormat)
3524 {
3525 // Read the section header to see how many clauses there are
3526 IMAGE_COR_ILMETHOD_SECT_FAT sectionHeader = { 0 };
3527 IfFailRet(GetProcess()->SafeReadStruct(ehClauseHeader, &sectionHeader));
3528 m_cClauses = (sectionHeader.DataSize - 4) / sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT);
3529 if (m_cClauses > 10000) // sanity check the data before allocating
3530 {
3531 return CORDBG_E_TARGET_INCONSISTENT;
3532 }
3533
3534 // Read in the clauses
3535 TargetBuffer buffer(ehClauseHeader + sizeof(IMAGE_COR_ILMETHOD_SECT_FAT), m_cClauses*sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT));
3536 NewArrayHolder<IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT> pClauses = new (nothrow)IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT[m_cClauses];
3537 if (pClauses == NULL)
3538 return E_OUTOFMEMORY;
3539 IfFailRet(GetProcess()->SafeReadBuffer(buffer, (BYTE*)pClauses.GetValue(), FALSE /*throwOnError*/));
3540
3541 // convert clauses
3542 m_pClauses = new (nothrow)CorDebugEHClause[m_cClauses];
3543 if (m_pClauses == NULL)
3544 return E_OUTOFMEMORY;
3545 for (ULONG32 i = 0; i < m_cClauses; i++)
3546 {
3547 BOOL isFilter = ((pClauses[i].Flags & COR_ILEXCEPTION_CLAUSE_FILTER) != 0);
3548 m_pClauses[i].Flags = pClauses[i].Flags;
3549 m_pClauses[i].TryOffset = pClauses[i].TryOffset;
3550 m_pClauses[i].TryLength = pClauses[i].TryLength;
3551 m_pClauses[i].HandlerOffset = pClauses[i].HandlerOffset;
3552 m_pClauses[i].HandlerLength = pClauses[i].HandlerLength;
3553 // these two fields are a union in the image, but are seperate in the struct ICorDebug returns
3554 m_pClauses[i].ClassToken = isFilter ? 0 : pClauses[i].ClassToken;
3555 m_pClauses[i].FilterOffset = isFilter ? pClauses[i].FilterOffset : 0;
3556 }
3557 }
3558 else
3559 {
3560 // Read in the section header to see how many small clauses there are
3561 IMAGE_COR_ILMETHOD_SECT_SMALL sectionHeader = { 0 };
3562 IfFailRet(GetProcess()->SafeReadStruct(ehClauseHeader, &sectionHeader));
3563 ULONG32 m_cClauses = (sectionHeader.DataSize - 4) / sizeof(IMAGE_COR_ILMETHOD_SECT_SMALL);
3564 if (m_cClauses > 10000) // sanity check the data before allocating
3565 {
3566 return CORDBG_E_TARGET_INCONSISTENT;
3567 }
3568
3569 // Read in the clauses
3570 TargetBuffer buffer(ehClauseHeader + sizeof(IMAGE_COR_ILMETHOD_SECT_SMALL), m_cClauses*sizeof(IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL));
3571 NewArrayHolder<IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL> pClauses = new (nothrow)IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_SMALL[m_cClauses];
3572 if (pClauses == NULL)
3573 return E_OUTOFMEMORY;
3574 IfFailRet(GetProcess()->SafeReadBuffer(buffer, (BYTE*)pClauses.GetValue(), FALSE /*throwOnError*/));
3575
3576 // convert clauses
3577 m_pClauses = new (nothrow)CorDebugEHClause[m_cClauses];
3578 if (m_pClauses == NULL)
3579 return E_OUTOFMEMORY;
3580 for (ULONG32 i = 0; i < m_cClauses; i++)
3581 {
3582 BOOL isFilter = ((pClauses[i].Flags & COR_ILEXCEPTION_CLAUSE_FILTER) != 0);
3583 m_pClauses[i].Flags = pClauses[i].Flags;
3584 m_pClauses[i].TryOffset = pClauses[i].TryOffset;
3585 m_pClauses[i].TryLength = pClauses[i].TryLength;
3586 m_pClauses[i].HandlerOffset = pClauses[i].HandlerOffset;
3587 m_pClauses[i].HandlerLength = pClauses[i].HandlerLength;
3588 // these two fields are a union in the image, but are seperate in the struct ICorDebug returns
3589 m_pClauses[i].ClassToken = isFilter ? 0 : pClauses[i].ClassToken;
3590 m_pClauses[i].FilterOffset = isFilter ? pClauses[i].FilterOffset : 0;
3591 }
3592 }
3593 return S_OK;
3594}
3595
3596#ifndef MIN
3597#define MIN(a,b) ((a) < (b) ? (a) : (b))
3598#endif
3599
3600//-----------------------------------------------------------------------------
3601// CordbReJitILCode::GetEHClauses
3602// Public method to get the EH clauses for IL code
3603//
3604// Parameters:
3605// cClauses - size of incoming clauses array (in elements).
3606// pcClauses - OUT param: cClauses>0 -> the number of elements written to in the clauses array.
3607// cClauses=0 -> the number of EH clauses this IL code has
3608// clauses - caller allocated storage to hold the EH clauses.
3609//
3610// Returns:
3611// S_OK if successfully copied elements to clauses array.
3612HRESULT CordbReJitILCode::GetEHClauses(ULONG32 cClauses, ULONG32 * pcClauses, CorDebugEHClause clauses[])
3613{
3614 PUBLIC_API_ENTRY(this);
3615 FAIL_IF_NEUTERED(this);
3616 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcClauses, ULONG32 *);
3617 VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(clauses, CorDebugEHClause *, cClauses, true, true);
3618 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3619
3620 if (cClauses != 0 && clauses == NULL)
3621 {
3622 return E_INVALIDARG;
3623 }
3624
3625 if (pcClauses != NULL)
3626 {
3627 if (cClauses == 0)
3628 {
3629 *pcClauses = m_cClauses;
3630 }
3631 else
3632 {
3633 *pcClauses = MIN(cClauses, m_cClauses);
3634 }
3635 }
3636
3637 if (clauses != NULL)
3638 {
3639 memcpy_s(clauses, sizeof(CorDebugEHClause)*cClauses, m_pClauses, sizeof(CorDebugEHClause)*MIN(cClauses, m_cClauses));
3640 }
3641 return S_OK;
3642}
3643
3644ULONG CordbReJitILCode::AddRef()
3645{
3646 return CordbCode::AddRef();
3647}
3648ULONG CordbReJitILCode::Release()
3649{
3650 return CordbCode::Release();
3651}
3652
3653HRESULT CordbReJitILCode::QueryInterface(REFIID riid, void** ppInterface)
3654{
3655 if (riid == IID_ICorDebugILCode)
3656 {
3657 *ppInterface = static_cast<ICorDebugILCode*>(this);
3658 }
3659 else if (riid == IID_ICorDebugILCode2)
3660 {
3661 *ppInterface = static_cast<ICorDebugILCode2*>(this);
3662 }
3663 else
3664 {
3665 return CordbILCode::QueryInterface(riid, ppInterface);
3666 }
3667
3668 AddRef();
3669 return S_OK;
3670}
3671
3672HRESULT CordbReJitILCode::GetLocalVarSigToken(mdSignature *pmdSig)
3673{
3674 PUBLIC_API_ENTRY(this);
3675 FAIL_IF_NEUTERED(this);
3676 VALIDATE_POINTER_TO_OBJECT(pmdSig, mdSignature *);
3677 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3678
3679 *pmdSig = m_localVarSigToken;
3680 return S_OK;
3681}
3682
3683HRESULT CordbReJitILCode::GetInstrumentedILMap(ULONG32 cMap, ULONG32 *pcMap, COR_IL_MAP map[])
3684{
3685 PUBLIC_API_ENTRY(this);
3686 FAIL_IF_NEUTERED(this);
3687 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcClauses, ULONG32 *);
3688 VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(map, COR_IL_MAP *, cMap, true, true);
3689 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
3690
3691 if (cMap != 0 && map == NULL)
3692 {
3693 return E_INVALIDARG;
3694 }
3695
3696 if (pcMap != NULL)
3697 {
3698 if (cMap == 0)
3699 {
3700 *pcMap = m_cILMap;
3701 }
3702 else
3703 {
3704 *pcMap = MIN(cMap, m_cILMap);
3705 }
3706 }
3707
3708 if (map != NULL)
3709 {
3710 memcpy_s(map, sizeof(COR_IL_MAP)*cMap, m_pILMap, sizeof(COR_IL_MAP)*MIN(cMap, m_cILMap));
3711 }
3712 return S_OK;
3713}
3714
3715// FindNativeInfoInILVariableArray
3716// Linear search through an array of NativeVarInfos, to find the variable of index dwIndex, valid
3717// at the given ip. Returns CORDBG_E_IL_VAR_NOT_AVAILABLE if the variable isn't valid at the given ip.
3718// Arguments:
3719// input: dwIndex - variable number
3720// ip - IP
3721// nativeInfoList - list of instances of NativeVarInfo
3722// output: ppNativeInfo - the element of nativeInfoList that corresponds to the IP and variable number
3723// if we find such an element or NULL otherwise
3724// Return value: HRESULT: returns S_OK or CORDBG_E_IL_VAR_NOT_AVAILABLE if the variable isn't found
3725//
3726HRESULT FindNativeInfoInILVariableArray(DWORD dwIndex,
3727 SIZE_T ip,
3728 const DacDbiArrayList<ICorDebugInfo::NativeVarInfo> * nativeInfoList,
3729 const ICorDebugInfo::NativeVarInfo ** ppNativeInfo)
3730{
3731 _ASSERTE(ppNativeInfo != NULL);
3732 *ppNativeInfo = NULL;
3733
3734 // A few words about this search: it must be linear, and the
3735 // comparison of startOffset and endOffset to ip must be
3736 // <=/>. startOffset points to the first instruction that will
3737 // make the variable's home valid. endOffset points to the first
3738 // instruction at which the variable's home invalid.
3739 int lastGoodOne = -1;
3740 for (unsigned int i = 0; i < (unsigned)nativeInfoList->Count(); i++)
3741 {
3742 if ((*nativeInfoList)[i].varNumber == dwIndex)
3743 {
3744 if ( (lastGoodOne == -1) ||
3745 ((*nativeInfoList)[lastGoodOne].startOffset < (*nativeInfoList)[i].startOffset) )
3746 {
3747 lastGoodOne = i;
3748 }
3749
3750 if (((*nativeInfoList)[i].startOffset <= ip) &&
3751 ((*nativeInfoList)[i].endOffset > ip))
3752 {
3753 *ppNativeInfo = &((*nativeInfoList)[i]);
3754
3755 return S_OK;
3756 }
3757 }
3758 }
3759
3760 // workaround:
3761 //
3762 // We didn't find the variable. Was the endOffset of the last range for this variable
3763 // equal to the current IP? If so, go ahead and "lie" and report that as the
3764 // variable's home for now.
3765 //
3766 // Rationale:
3767 //
3768 // * See TODO comment in code:Compiler::siUpdate (jit\scopeinfo.cpp). In optimized
3769 // code, the JIT can report var lifetimes as being one instruction too short.
3770 // This workaround makes up for that. Example code:
3771 //
3772 // static void foo(int x)
3773 // {
3774 // int b = x; // Value of "x" would not be reported in optimized code without the workaround
3775 // bar(ref b);
3776 // }
3777 //
3778 // * Since this is the first instruction after the last range a variable was alive,
3779 // we're essentially assuming that since that instruction hasn't been executed
3780 // yet, and since there isn't a new home for the variable, that the last home is
3781 // still good. This actually turns out to be true 99.9% of the time, so we'll go
3782 // with it for now.
3783 // * We've been lying like this since 1999, so surely it's safe.
3784 if ((lastGoodOne > -1) && ((*nativeInfoList)[lastGoodOne].endOffset == ip))
3785 {
3786 *ppNativeInfo = &((*nativeInfoList)[lastGoodOne]);
3787 return S_OK;
3788 }
3789
3790 return CORDBG_E_IL_VAR_NOT_AVAILABLE;
3791} // FindNativeInfoInILVariableArray
3792
3793
3794// * ------------------------------------------------------------------------- *
3795// * Variable Enum class
3796// * ------------------------------------------------------------------------- *
3797//-----------------------------------------------------------------------------
3798// CordbVariableHome constructor
3799// Arguments:
3800// Input:
3801// pCode - CordbNativeCode instance containing this variable home
3802// pNativeVarInfo - native location, lifetime, and index information for
3803// this variable
3804// isLocal - indicates whether the instance is a local variable,
3805// as opposed to an argument
3806// index - the argument or slot index
3807// Output:
3808// fields of the CordbVariableHome instance have been initialized
3809//-----------------------------------------------------------------------------
3810CordbVariableHome::CordbVariableHome(CordbNativeCode *pCode,
3811 const ICorDebugInfo::NativeVarInfo nativeVarInfo,
3812 BOOL isLocal,
3813 ULONG index) :
3814 CordbBase(pCode->GetModule()->GetProcess(), 0)
3815{
3816 _ASSERTE(pCode != NULL);
3817
3818 m_pCode.Assign(pCode);
3819 m_nativeVarInfo = nativeVarInfo;
3820 m_isLocal = isLocal;
3821 m_index = index;
3822}
3823
3824CordbVariableHome::~CordbVariableHome()
3825{
3826 _ASSERTE(this->IsNeutered());
3827}
3828
3829void CordbVariableHome::Neuter()
3830{
3831 m_pCode.Clear();
3832 CordbBase::Neuter();
3833}
3834
3835//-----------------------------------------------------------------------------
3836// Public method for IUnknown::QueryInterface.
3837// Has standard QI semantics.
3838//-----------------------------------------------------------------------------
3839HRESULT CordbVariableHome::QueryInterface(REFIID id, void **pInterface)
3840{
3841 if (id == IID_ICorDebugVariableHome)
3842 {
3843 *pInterface = static_cast<ICorDebugVariableHome *>(this);
3844 }
3845 else if (id == IID_IUnknown)
3846 {
3847 *pInterface = static_cast<IUnknown *>(static_cast<ICorDebugVariableHome *>(this));
3848 }
3849 else
3850 {
3851 *pInterface = NULL;
3852 return E_NOINTERFACE;
3853 }
3854
3855 ExternalAddRef();
3856 return S_OK;
3857}
3858
3859//-----------------------------------------------------------------------------
3860// CordbVariableHome::GetCode
3861// Public method to get the Code object containing this variable home.
3862//
3863// Parameters:
3864// ppCode - OUT: returns the Code object for this variable home.
3865//
3866// Returns:
3867// S_OK - on success.
3868//-----------------------------------------------------------------------------
3869HRESULT CordbVariableHome::GetCode(ICorDebugCode **ppCode)
3870{
3871 PUBLIC_REENTRANT_API_ENTRY(this);
3872 FAIL_IF_NEUTERED(this);
3873 VALIDATE_POINTER_TO_OBJECT(ppCode, ICorDebugCode **);
3874 ATT_REQUIRE_STOPPED_MAY_FAIL(m_pCode->GetProcess());
3875
3876 HRESULT hr = m_pCode->QueryInterface(IID_ICorDebugCode, (LPVOID*)ppCode);
3877
3878 return hr;
3879}
3880
3881//-----------------------------------------------------------------------------
3882// CordbVariableHome::GetSlotIndex
3883// Public method to get the slot index for this variable home.
3884//
3885// Parameters:
3886// pSlotIndex - OUT: returns the managed slot-index of this variable home.
3887//
3888// Returns:
3889// S_OK - on success
3890// E_FAIL - if the variable is not a local variable, but an argument
3891//-----------------------------------------------------------------------------
3892HRESULT CordbVariableHome::GetSlotIndex(ULONG32 *pSlotIndex)
3893{
3894 PUBLIC_REENTRANT_API_ENTRY(this);
3895 FAIL_IF_NEUTERED(this);
3896 VALIDATE_POINTER_TO_OBJECT(pSlotIndex, ULONG32 *);
3897 ATT_REQUIRE_STOPPED_MAY_FAIL(m_pCode->GetProcess());
3898
3899 if (!m_isLocal)
3900 {
3901 return E_FAIL;
3902 }
3903 *pSlotIndex = m_index;
3904 return S_OK;
3905}
3906
3907//-----------------------------------------------------------------------------
3908// CordbVariableHome::GetArgumentIndex
3909// Public method to get the slot index for this variable home.
3910//
3911// Parameters:
3912// pSlotIndex - OUT: returns the managed argument-index of this variable home.
3913//
3914// Returns:
3915// S_OK - on success
3916// E_FAIL - if the variable is not an argument, but a local variable
3917//-----------------------------------------------------------------------------
3918HRESULT CordbVariableHome::GetArgumentIndex(ULONG32 *pArgumentIndex)
3919{
3920 PUBLIC_REENTRANT_API_ENTRY(this);
3921 FAIL_IF_NEUTERED(this);
3922 VALIDATE_POINTER_TO_OBJECT(pArgumentIndex, ULONG32 *);
3923 ATT_REQUIRE_STOPPED_MAY_FAIL(m_pCode->GetProcess());
3924
3925 if (m_isLocal)
3926 {
3927 return E_FAIL;
3928 }
3929 *pArgumentIndex = m_index;
3930 return S_OK;
3931}
3932
3933//-----------------------------------------------------------------------------
3934// CordbVariableHome::GetLiveRange
3935// Public method to get the native range over which this variable is live.
3936//
3937// Parameters:
3938// pStartOffset - OUT: returns the logical offset at which the variable is
3939// first live
3940// pEndOffset - OUT: returns the logical offset immediately after that at
3941// which the variable is last live
3942//
3943// Returns:
3944// S_OK - on success
3945//-----------------------------------------------------------------------------
3946HRESULT CordbVariableHome::GetLiveRange(ULONG32 *pStartOffset,
3947 ULONG32 *pEndOffset)
3948{
3949 PUBLIC_REENTRANT_API_ENTRY(this);
3950 FAIL_IF_NEUTERED(this);
3951 VALIDATE_POINTER_TO_OBJECT(pStartOffset, ULONG32 *);
3952 VALIDATE_POINTER_TO_OBJECT(pEndOffset, ULONG32 *);
3953 ATT_REQUIRE_STOPPED_MAY_FAIL(m_pCode->GetProcess());
3954
3955 *pStartOffset = m_nativeVarInfo.startOffset;
3956 *pEndOffset = m_nativeVarInfo.endOffset;
3957 return S_OK;
3958}
3959
3960//-----------------------------------------------------------------------------
3961// CordbVariableHome::GetLocationType
3962// Public method to get the type of native location for this variable home.
3963//
3964// Parameters:
3965// pLocationType - OUT: the type of native location
3966//
3967// Returns:
3968// S_OK - on success
3969//-----------------------------------------------------------------------------
3970HRESULT CordbVariableHome::GetLocationType(VariableLocationType *pLocationType)
3971{
3972 PUBLIC_REENTRANT_API_ENTRY(this);
3973 FAIL_IF_NEUTERED(this);
3974 VALIDATE_POINTER_TO_OBJECT(pLocationType, VariableLocationType *);
3975 ATT_REQUIRE_STOPPED_MAY_FAIL(m_pCode->GetProcess());
3976
3977 switch (m_nativeVarInfo.loc.vlType)
3978 {
3979 case ICorDebugInfo::VLT_REG:
3980 *pLocationType = VLT_REGISTER;
3981 break;
3982 case ICorDebugInfo::VLT_STK:
3983 *pLocationType = VLT_REGISTER_RELATIVE;
3984 break;
3985 default:
3986 *pLocationType = VLT_INVALID;
3987 }
3988 return S_OK;
3989}
3990
3991//-----------------------------------------------------------------------------
3992// CordbVariableHome::GetRegister
3993// Public method to get the register or base register for this variable hom.
3994//
3995// Parameters:
3996// pRegister - OUT: for VLT_REGISTER location types, gives the register.
3997// for VLT_REGISTER_RELATIVE location types, gives the base
3998// register.
3999//
4000// Returns:
4001// S_OK - on success
4002// E_FAIL - for VLT_INVALID location types
4003//-----------------------------------------------------------------------------
4004HRESULT CordbVariableHome::GetRegister(CorDebugRegister *pRegister)
4005{
4006 PUBLIC_REENTRANT_API_ENTRY(this);
4007 FAIL_IF_NEUTERED(this);
4008 VALIDATE_POINTER_TO_OBJECT(pRegister, CorDebugRegister *);
4009 ATT_REQUIRE_STOPPED_MAY_FAIL(m_pCode->GetProcess());
4010
4011 switch (m_nativeVarInfo.loc.vlType)
4012 {
4013 case ICorDebugInfo::VLT_REG:
4014 *pRegister = ConvertRegNumToCorDebugRegister(m_nativeVarInfo.loc.vlReg.vlrReg);
4015 break;
4016 case ICorDebugInfo::VLT_STK:
4017 *pRegister = ConvertRegNumToCorDebugRegister(m_nativeVarInfo.loc.vlStk.vlsBaseReg);
4018 break;
4019 default:
4020 return E_FAIL;
4021 }
4022 return S_OK;
4023}
4024
4025//-----------------------------------------------------------------------------
4026// CordbVariableHome::GetOffset
4027// Public method to get the offset from the base register for this variable home.
4028//
4029// Parameters:
4030// pOffset - OUT: gives the offset from the base register
4031//
4032// Returns:
4033// S_OK - on success
4034// E_FAIL - for location types other than VLT_REGISTER_RELATIVE
4035//-----------------------------------------------------------------------------
4036HRESULT CordbVariableHome::GetOffset(LONG *pOffset)
4037{
4038 PUBLIC_REENTRANT_API_ENTRY(this);
4039 FAIL_IF_NEUTERED(this);
4040 VALIDATE_POINTER_TO_OBJECT(pOffset, LONG *);
4041 ATT_REQUIRE_STOPPED_MAY_FAIL(m_pCode->GetProcess());
4042
4043 switch (m_nativeVarInfo.loc.vlType)
4044 {
4045 case ICorDebugInfo::VLT_STK:
4046 *pOffset = m_nativeVarInfo.loc.vlStk.vlsOffset;
4047 break;
4048 default:
4049 return E_FAIL;
4050 }
4051 return S_OK;
4052}
4053
4054
4055// * ------------------------------------------------------------------------- *
4056// * Native Code class
4057// * ------------------------------------------------------------------------- */
4058
4059
4060//-----------------------------------------------------------------------------
4061// CordbNativeCode ctor to make Native code.
4062// Arguments:
4063// Input:
4064// pFunction - the function for which this is the native code object
4065// pJitData - the information about this code object retrieved from the DAC
4066// fIsInstantiatedGeneric - indicates whether this code object is an instantiated
4067// generic
4068// Output:
4069// fields of this instance of CordbNativeCode have been initialized
4070//-----------------------------------------------------------------------------
4071CordbNativeCode::CordbNativeCode(CordbFunction * pFunction,
4072 const NativeCodeFunctionData * pJitData,
4073 BOOL fIsInstantiatedGeneric)
4074 : CordbCode(pFunction, (UINT_PTR)pJitData->m_rgCodeRegions[kHot].pAddress, pJitData->encVersion, FALSE),
4075 m_vmNativeCodeMethodDescToken(pJitData->vmNativeCodeMethodDescToken),
4076 m_fCodeAvailable(TRUE),
4077 m_fIsInstantiatedGeneric(fIsInstantiatedGeneric != FALSE)
4078{
4079 _ASSERTE(GetVersion() >= CorDB_DEFAULT_ENC_FUNCTION_VERSION);
4080
4081 for (CodeBlobRegion region = kHot; region < MAX_REGIONS; ++region)
4082 {
4083 m_rgCodeRegions[region] = pJitData->m_rgCodeRegions[region];
4084 }
4085} //CordbNativeCode::CordbNativeCode
4086
4087//-----------------------------------------------------------------------------
4088// Public method for IUnknown::QueryInterface.
4089// Has standard QI semantics.
4090//-----------------------------------------------------------------------------
4091HRESULT CordbNativeCode::QueryInterface(REFIID id, void ** pInterface)
4092{
4093 if (id == IID_ICorDebugCode)
4094 {
4095 *pInterface = static_cast<ICorDebugCode *>(this);
4096 }
4097 else if (id == IID_ICorDebugCode2)
4098 {
4099 *pInterface = static_cast<ICorDebugCode2 *>(this);
4100 }
4101 else if (id == IID_ICorDebugCode3)
4102 {
4103 *pInterface = static_cast<ICorDebugCode3 *>(this);
4104 }
4105 else if (id == IID_ICorDebugCode4)
4106 {
4107 *pInterface = static_cast<ICorDebugCode4 *>(this);
4108 }
4109 else if (id == IID_IUnknown)
4110 {
4111 *pInterface = static_cast<IUnknown *>(static_cast<ICorDebugCode *>(this));
4112 }
4113 else
4114 {
4115 *pInterface = NULL;
4116 return E_NOINTERFACE;
4117 }
4118
4119 ExternalAddRef();
4120 return S_OK;
4121}
4122
4123//-----------------------------------------------------------------------------
4124// CordbNativeCode::GetAddress
4125// Public method to get the Entry address for the code. This is the address
4126// where the method first starts executing.
4127//
4128// Parameters:
4129// pStart - out-parameter to hold start address.
4130//
4131// Returns:
4132// S_OK if *pStart is properly updated.
4133//-----------------------------------------------------------------------------
4134HRESULT CordbNativeCode::GetAddress(CORDB_ADDRESS * pStart)
4135{
4136 PUBLIC_REENTRANT_API_ENTRY(this);
4137 FAIL_IF_NEUTERED(this);
4138 VALIDATE_POINTER_TO_OBJECT(pStart, CORDB_ADDRESS *);
4139
4140
4141 _ASSERTE(this != NULL);
4142 _ASSERTE(this->GetFunction() != NULL);
4143 _ASSERTE(this->GetFunction()->GetModule() != NULL);
4144 _ASSERTE(this->GetFunction()->GetModule()->GetProcess() == GetProcess());
4145
4146 // Since we don't do code-pitching, the address points directly to the code.
4147 *pStart = (m_rgCodeRegions[kHot].pAddress);
4148
4149 if (*pStart == NULL)
4150 {
4151 return CORDBG_E_CODE_NOT_AVAILABLE;
4152 }
4153 return S_OK;
4154} // CordbNativeCode::GetAddress
4155
4156//-----------------------------------------------------------------------------
4157// CordbNativeCode::ReadCodeBytes
4158// Reads the actual bytes of native code from both the hot and cold regions
4159// into the data member m_rgbCode
4160// Arguments:
4161// none (uses data members)
4162// Return value:
4163// standard HRESULT values
4164// also allocates and initializes m_rgbCode
4165// Notes: assumes that the caller has checked to ensure that m_rgbCode doesn't
4166// hold valid data
4167//-----------------------------------------------------------------------------
4168HRESULT CordbNativeCode::ReadCodeBytes()
4169{
4170 HRESULT hr = S_OK;
4171
4172 EX_TRY
4173 {
4174 // We have an address & size, so we'll just call ReadMemory.
4175 // This will conveniently strip out any patches too.
4176 CORDB_ADDRESS pHotStart = m_rgCodeRegions[kHot].pAddress;
4177 CORDB_ADDRESS pColdStart = m_rgCodeRegions[kCold].pAddress;
4178 ULONG32 cbHotSize = (ULONG32) m_rgCodeRegions[kHot].cbSize;
4179 ULONG32 cbColdSize = GetColdSize();
4180
4181 delete [] m_rgbCode;
4182 m_rgbCode = new BYTE[cbHotSize + cbColdSize];
4183
4184 SIZE_T cbRead;
4185 hr = GetProcess()->ReadMemory(pHotStart, cbHotSize, m_rgbCode, &cbRead);
4186 IfFailThrow(hr);
4187
4188 SIMPLIFYING_ASSUMPTION(cbRead == cbHotSize);
4189
4190 if (HasColdRegion())
4191 {
4192 hr = GetProcess()->ReadMemory(pColdStart, cbColdSize, (BYTE *) m_rgbCode + cbHotSize, &cbRead);
4193 IfFailThrow(hr);
4194
4195 SIMPLIFYING_ASSUMPTION(cbRead == cbColdSize);
4196 }
4197 }
4198 EX_CATCH_HRESULT(hr);
4199 return hr;
4200
4201} // CordbNativeCode::ReadCodeBytes
4202
4203//-----------------------------------------------------------------------------
4204// CordbNativeCode::GetColdSize
4205// Get the size of the cold regions in bytes.
4206//
4207// Parameters:
4208// none--uses data member m_rgCodeRegions to compute total size.
4209//
4210// Returns:
4211// the size of the code in bytes.
4212//-----------------------------------------------------------------------------
4213ULONG32 CordbNativeCode::GetColdSize()
4214{
4215 ULONG32 pcBytes = 0;
4216 for (CodeBlobRegion index = kCold; index < MAX_REGIONS; ++index)
4217 {
4218 pcBytes += m_rgCodeRegions[index].cbSize;
4219 }
4220 return pcBytes;
4221} // CordbNativeCode::GetColdSize
4222
4223//-----------------------------------------------------------------------------
4224// CordbNativeCode::GetSize
4225// Get the size of the code in bytes.
4226//
4227// Parameters:
4228// none--uses data member m_rgCodeRegions to compute total size.
4229//
4230// Returns:
4231// the size of the code in bytes.
4232//-----------------------------------------------------------------------------
4233ULONG32 CordbNativeCode::GetSize()
4234{
4235 ULONG32 pcBytes = 0;
4236 for (CodeBlobRegion index = kHot; index < MAX_REGIONS; ++index)
4237 {
4238 pcBytes += m_rgCodeRegions[index].cbSize;
4239 }
4240 return pcBytes;
4241} // CordbNativeCode::GetSize
4242
4243//-----------------------------------------------------------------------------
4244// CordbNativeCode::GetILToNativeMapping
4245// Public method (implements ICorDebugCode) to get the IL-->{ Native Start, Native End} mapping.
4246// This can only be retrieved for native code.
4247// This will copy as much of the map as can fit in the incoming buffer.
4248//
4249// Parameters:
4250// cMap - size of incoming map[] array (in elements).
4251// pcMap - OUT: full size of IL-->Native map (in elements).
4252// map - caller allocated array to be filled in.
4253//
4254// Returns:
4255// S_OK on successful copying.
4256//-----------------------------------------------------------------------------
4257HRESULT CordbNativeCode::GetILToNativeMapping(ULONG32 cMap,
4258 ULONG32 * pcMap,
4259 COR_DEBUG_IL_TO_NATIVE_MAP map[])
4260{
4261 PUBLIC_REENTRANT_API_ENTRY(this);
4262 FAIL_IF_NEUTERED(this);
4263 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pcMap, ULONG32 *);
4264 VALIDATE_POINTER_TO_OBJECT_ARRAY_OR_NULL(map, COR_DEBUG_IL_TO_NATIVE_MAP *,cMap,true,true);
4265
4266 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4267
4268 HRESULT hr = S_OK;
4269 EX_TRY
4270 {
4271 LoadNativeInfo();
4272
4273 SequencePoints * pSeqPts = GetSequencePoints();
4274 DebuggerILToNativeMap * rgMapInt = pSeqPts->GetMapAddr();
4275 ULONG32 cMapIntCount = pSeqPts->GetEntryCount();
4276
4277 // If they gave us space to copy into...
4278 if (map != NULL)
4279 {
4280 // Only copy as much as either they gave us or we have to copy.
4281 ULONG32 cMapToCopy = min(cMap, cMapIntCount);
4282
4283 // Remember that we need to translate between our internal DebuggerILToNativeMap and the external
4284 // COR_DEBUG_IL_TO_NATIVE_MAP!
4285 ULONG32 size = GetSize();
4286 ExportILToNativeMap(cMapToCopy, map, rgMapInt, size);
4287 }
4288
4289 // return the full count of map entries
4290 if (pcMap)
4291 {
4292 *pcMap = cMapIntCount;
4293 }
4294 }
4295 EX_CATCH_HRESULT(hr);
4296 return hr;
4297} // CordbNativeCode::GetILToNativeMapping
4298
4299//-----------------------------------------------------------------------------
4300// CordbNativeCode::GetCodeChunks
4301// Public method to get the code regions of code. If the code
4302// is broken into discontinuous regions (hot + cold), this lets a debugger
4303// find the number of regions, and (start,size) of each.
4304//
4305// Parameters:
4306// cbufSize - size of incoming chunks array (in elements).
4307// pcnumChunks - OUT param: the number of elements written to in the chunk array.//
4308// chunks - caller allocated storage to hold the code chunks.
4309//
4310// Returns:
4311// S_OK if successfully copied elements to Chunk array.
4312//-----------------------------------------------------------------------------
4313HRESULT CordbNativeCode::GetCodeChunks(
4314 ULONG32 cbufSize,
4315 ULONG32 * pcnumChunks,
4316 CodeChunkInfo chunks[]
4317)
4318{
4319 PUBLIC_API_ENTRY(this);
4320
4321 if (pcnumChunks == NULL)
4322 {
4323 return E_INVALIDARG;
4324 }
4325 if ((chunks == NULL) != (cbufSize == 0))
4326 {
4327 return E_INVALIDARG;
4328 }
4329
4330 // Current V2.0 implementation has at most 2 possible chunks right now (1 hot, and 1 cold).
4331 ULONG32 cActualChunks = HasColdRegion() ? 2 : 1;
4332
4333 // If no buf size, then we're querying the total number of chunks.
4334 if (cbufSize == 0)
4335 {
4336 *pcnumChunks = cActualChunks;
4337 return S_OK;
4338 }
4339
4340 // Else give them as many as they asked for.
4341 for (CodeBlobRegion index = kHot; (index < MAX_REGIONS) && ((int)cbufSize > index); ++index)
4342 {
4343 // Fill in the region information
4344 chunks[index].startAddr = m_rgCodeRegions[index].pAddress;
4345 chunks[index].length = (ULONG32) (m_rgCodeRegions[index].cbSize);
4346 *pcnumChunks = cbufSize;
4347 }
4348
4349 return S_OK;
4350} // CordbNativeCode::GetCodeChunks
4351
4352//-----------------------------------------------------------------------------
4353// CordbNativeCode::GetCompilerFlags
4354// Public entry point to get code flags for this Code object.
4355// Originally, ICDCode had this method implemented independently from the
4356// ICDModule method GetJitCompilerFlags. This was because it was considered that
4357// the flags would be per function, rather than per module.
4358// In addition, GetCompilerFlags did two different things depending on whether
4359// the code had a native image. It turned out that was the wrong thing to do
4360// .
4361//
4362// Parameters:
4363// pdwFlags - OUT: code gen flags (see CorDebugJITCompilerFlags)
4364//
4365// Return value:
4366// S_OK if pdwFlags is set properly.
4367//-----------------------------------------------------------------------------
4368HRESULT CordbNativeCode::GetCompilerFlags(DWORD * pdwFlags)
4369{
4370 PUBLIC_API_ENTRY(this);
4371 FAIL_IF_NEUTERED(this);
4372 VALIDATE_POINTER_TO_OBJECT(pdwFlags, DWORD *);
4373 *pdwFlags = 0;
4374 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4375
4376 return GetFunction()->GetModule()->GetJITCompilerFlags(pdwFlags);
4377
4378} // CordbNativeCode::GetCompilerFlags
4379
4380//-----------------------------------------------------------------------------
4381// Given an IL local variable number and a native IP offset, return the
4382// location of the variable in jitted code.
4383//-----------------------------------------------------------------------------
4384HRESULT CordbNativeCode::ILVariableToNative(DWORD dwIndex,
4385 SIZE_T ip,
4386 const ICorDebugInfo::NativeVarInfo ** ppNativeInfo)
4387{
4388 _ASSERTE(m_nativeVarData.IsInitialized());
4389
4390 return FindNativeInfoInILVariableArray(dwIndex,
4391 ip,
4392 m_nativeVarData.GetOffsetInfoList(),
4393 ppNativeInfo);
4394} // CordbNativeCode::ILVariableToNative
4395
4396
4397HRESULT CordbNativeCode::GetReturnValueLiveOffset(ULONG32 ILoffset, ULONG32 bufferSize, ULONG32 *pFetched, ULONG32 *pOffsets)
4398{
4399 HRESULT hr = S_OK;
4400
4401 PUBLIC_API_ENTRY(this);
4402 FAIL_IF_NEUTERED(this);
4403
4404 VALIDATE_POINTER_TO_OBJECT(pFetched, ULONG32 *);
4405
4406 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4407 EX_TRY
4408 {
4409 hr = GetReturnValueLiveOffsetImpl(NULL, ILoffset, bufferSize, pFetched, pOffsets);
4410 }
4411 EX_CATCH_HRESULT(hr);
4412 return hr;
4413}
4414
4415//-----------------------------------------------------------------------------
4416// CordbNativeCode::EnumerateVariableHomes
4417// Public method to get an enumeration of native variable homes. This may
4418// include multiple ICorDebugVariableHomes for the same slot or argument index
4419// if they have different homes at different points in the function.
4420//
4421// Parameters:
4422// ppEnum - OUT: returns the enum of variable homes.
4423//
4424// Returns:
4425// HRESULT for success or failure.
4426//-----------------------------------------------------------------------------
4427HRESULT CordbNativeCode::EnumerateVariableHomes(ICorDebugVariableHomeEnum **ppEnum)
4428{
4429 PUBLIC_REENTRANT_API_ENTRY(this);
4430 FAIL_IF_NEUTERED(this);
4431 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugVariableHomeEnum **);
4432 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
4433
4434 HRESULT hr = S_OK;
4435
4436 // Get the argument count
4437 ULONG argCount = 0;
4438 CordbFunction *func = GetFunction();
4439 _ASSERTE(func != NULL);
4440 IfFailRet(func->GetSig(NULL, &argCount, NULL));
4441
4442#ifdef _DEBUG
4443 // Get the number of locals
4444 ULONG localCount = 0;
4445 EX_TRY
4446 {
4447 GetFunction()->GetILCode()->GetLocalVarSig(NULL, &localCount);
4448 }
4449 EX_CATCH_HRESULT(hr);
4450 IfFailRet(hr);
4451#endif
4452
4453 RSSmartPtr<CordbVariableHome> *rsHomes = NULL;
4454
4455 EX_TRY
4456 {
4457 CordbProcess *pProcess = GetProcess();
4458 _ASSERTE(pProcess != NULL);
4459
4460 const DacDbiArrayList<ICorDebugInfo::NativeVarInfo> *pOffsetInfoList = m_nativeVarData.GetOffsetInfoList();
4461 _ASSERTE(pOffsetInfoList != NULL);
4462 DWORD countHomes = 0;
4463 for (int i = 0; i < pOffsetInfoList->Count(); i++)
4464 {
4465 const ICorDebugInfo::NativeVarInfo *pNativeVarInfo = &((*pOffsetInfoList)[i]);
4466 _ASSERTE(pNativeVarInfo != NULL);
4467
4468 // The variable information list can include variables
4469 // with special varNumbers representing, for instance, the
4470 // parameter types for generic methods. Here we are only
4471 // interested in local variables and arguments.
4472 if (pNativeVarInfo->varNumber < (DWORD)ICorDebugInfo::MAX_ILNUM)
4473 {
4474 countHomes++;
4475 }
4476 }
4477 rsHomes = new RSSmartPtr<CordbVariableHome>[countHomes];
4478
4479 DWORD varHomeInd = 0;
4480 for (int i = 0; i < pOffsetInfoList->Count(); i++)
4481 {
4482 const ICorDebugInfo::NativeVarInfo *pNativeVarInfo = &((*pOffsetInfoList)[i]);
4483
4484 // Again, only look for native var info representing local
4485 // variables and arguments.
4486 if (pNativeVarInfo->varNumber < (DWORD)ICorDebugInfo::MAX_ILNUM)
4487 {
4488 // determine whether this variable home represents and argument or local variable
4489 BOOL isLocal = ((ULONG)pNativeVarInfo->varNumber >= argCount);
4490
4491 // determine the argument-index or slot-index of this variable home
4492 ULONG argOrSlotIndex;
4493 if (isLocal) {
4494 argOrSlotIndex = pNativeVarInfo->varNumber - argCount;
4495 _ASSERTE(argOrSlotIndex < localCount);
4496 } else {
4497 argOrSlotIndex = pNativeVarInfo->varNumber;
4498 }
4499
4500 RSInitHolder<CordbVariableHome> pCVH(new CordbVariableHome(this,
4501 (*pOffsetInfoList)[i],
4502 isLocal,
4503 argOrSlotIndex));
4504 pProcess->GetContinueNeuterList()->Add(pProcess, pCVH);
4505 _ASSERTE(varHomeInd < countHomes);
4506 rsHomes[varHomeInd].Assign(pCVH);
4507 pCVH.ClearAndMarkDontNeuter();
4508 varHomeInd++;
4509 }
4510 }
4511
4512 RSInitHolder<CordbVariableHomeEnumerator> pCDVHE(
4513 new CordbVariableHomeEnumerator(GetProcess(), &rsHomes, countHomes));
4514 pProcess->GetContinueNeuterList()->Add(pProcess, pCDVHE);
4515 pCDVHE.TransferOwnershipExternal(ppEnum);
4516 }
4517 EX_CATCH_HRESULT(hr);
4518
4519 return hr;
4520}
4521
4522int CordbNativeCode::GetCallInstructionLength(BYTE *ip, ULONG32 count)
4523{
4524#if defined(DBG_TARGET_ARM)
4525 if (Is32BitInstruction(*(WORD*)ip))
4526 return 4;
4527 else
4528 return 2;
4529#elif defined(DBG_TARGET_ARM64)
4530 return MAX_INSTRUCTION_LENGTH;
4531#elif defined(DBG_TARGET_X86)
4532 if (count < 2)
4533 return -1;
4534
4535 // Skip instruction prefixes
4536 do
4537 {
4538 switch (*ip)
4539 {
4540 // Segment overrides
4541 case 0x26: // ES
4542 case 0x2E: // CS
4543 case 0x36: // SS
4544 case 0x3E: // DS
4545 case 0x64: // FS
4546 case 0x65: // GS
4547
4548 // Size overrides
4549 case 0x66: // Operand-Size
4550 case 0x67: // Address-Size
4551
4552 // Lock
4553 case 0xf0:
4554
4555 // String REP prefixes
4556 case 0xf1:
4557 case 0xf2: // REPNE/REPNZ
4558 case 0xf3:
4559 ip++;
4560 count--;
4561 continue;
4562
4563 default:
4564 break;
4565 }
4566 } while (0);
4567
4568 // Read the opcode
4569 BYTE opcode = *ip++;
4570 if (opcode == 0xcc)
4571 {
4572 // todo: Can we actually get this result? Doesn't ICorDebug hand out un-patched assembly?
4573 _ASSERTE(!"Hit break opcode!");
4574 return -1;
4575 }
4576
4577 // Analyze what we can of the opcode
4578 switch (opcode)
4579 {
4580 case 0xff:
4581 {
4582 // Count may have been decremented by prefixes.
4583 if (count < 2)
4584 return -1;
4585
4586 BYTE modrm = *ip++;
4587 BYTE mod = (modrm & 0xC0) >> 6;
4588 BYTE reg = (modrm & 0x38) >> 3;
4589 BYTE rm = (modrm & 0x07);
4590
4591 int displace = -1;
4592
4593 if ((reg != 2) && (reg != 3) && (reg != 4) && (reg != 5))
4594 {
4595 //
4596 // This is not a CALL or JMP instruction, return, unknown.
4597 //
4598 _ASSERTE(!"Unhandled opcode!");
4599 return -1;
4600 }
4601
4602
4603 // Only try to decode registers if we actually have reg sets.
4604 switch (mod)
4605 {
4606 case 0:
4607 case 1:
4608 case 2:
4609
4610 if (rm == 4)
4611 {
4612 if (count < 3)
4613 return -1;
4614
4615 //
4616 // Get values from the SIB byte
4617 //
4618 BYTE ss = (*ip & 0xC0) >> 6;
4619 BYTE index = (*ip & 0x38) >> 3;
4620 BYTE base = (*ip & 0x7);
4621
4622 //
4623 // Finally add in the offset
4624 //
4625 if (mod == 0)
4626 {
4627 if (base == 5)
4628 displace = 7;
4629 else
4630 displace = 3;
4631 }
4632 else if (mod == 1)
4633 {
4634 displace = 4;
4635 }
4636 else
4637 {
4638 displace = 7;
4639 }
4640 }
4641 else
4642 {
4643 if (mod == 0)
4644 {
4645 if (rm == 5)
4646 displace = 6;
4647 else
4648 displace = 2;
4649 }
4650 else if (mod == 1)
4651 {
4652 displace = 3;
4653 }
4654 else
4655 {
4656 displace = 6;
4657 }
4658 }
4659 break;
4660
4661 case 3:
4662 default:
4663 displace = 2;
4664 break;
4665 }
4666
4667 return displace;
4668 } // end of 0xFF case
4669
4670 case 0xe8:
4671 return 5;
4672
4673
4674 default:
4675 break;
4676 }
4677
4678
4679 _ASSERTE(!"Unhandled opcode!");
4680 return -1;
4681
4682#elif defined(DBG_TARGET_AMD64)
4683 BYTE rex = NULL;
4684 BYTE prefix = *ip;
4685 BOOL fContainsPrefix = FALSE;
4686
4687 // Should not happen.
4688 if (prefix == 0xcc)
4689 return -1;
4690
4691 // Skip instruction prefixes
4692 //@TODO by euzem:
4693 //This "loop" can't be really executed more than once so if CALL can really have more than one prefix we'll crash.
4694 //Some of these prefixes are not allowed for CALL instruction and we should treat them as invalid code.
4695 //It appears that this code was mostly copy/pasted from \NDP\clr\src\Debug\EE\amd64\amd64walker.cpp
4696 //with very minimum fixes.
4697 do
4698 {
4699 switch (prefix)
4700 {
4701 // Segment overrides
4702 case 0x26: // ES
4703 case 0x2E: // CS
4704 case 0x36: // SS
4705 case 0x3E: // DS
4706 case 0x64: // FS
4707 case 0x65: // GS
4708
4709 // Size overrides
4710 case 0x66: // Operand-Size
4711 case 0x67: // Address-Size
4712
4713 // Lock
4714 case 0xf0:
4715
4716 // String REP prefixes
4717 case 0xf2: // REPNE/REPNZ
4718 case 0xf3:
4719 ip++;
4720 fContainsPrefix = TRUE;
4721 continue;
4722
4723 // REX register extension prefixes
4724 case 0x40:
4725 case 0x41:
4726 case 0x42:
4727 case 0x43:
4728 case 0x44:
4729 case 0x45:
4730 case 0x46:
4731 case 0x47:
4732 case 0x48:
4733 case 0x49:
4734 case 0x4a:
4735 case 0x4b:
4736 case 0x4c:
4737 case 0x4d:
4738 case 0x4e:
4739 case 0x4f:
4740 // make sure to set rex to prefix, not *ip because *ip still represents the
4741 // codestream which has a 0xcc in it.
4742 rex = prefix;
4743 ip++;
4744 fContainsPrefix = TRUE;
4745 continue;
4746
4747 default:
4748 break;
4749 }
4750 } while (0);
4751
4752 // Read the opcode
4753 BYTE opcode = *ip++;
4754
4755 // Should not happen.
4756 if (opcode == 0xcc)
4757 return -1;
4758
4759
4760 // Setup rex bits if needed
4761 BYTE rex_b = 0;
4762 BYTE rex_x = 0;
4763 BYTE rex_r = 0;
4764
4765 if (rex != NULL)
4766 {
4767 rex_b = (rex & 0x1); // high bit to modrm r/m field or SIB base field or OPCODE reg field -- Hmm, when which?
4768 rex_x = (rex & 0x2) >> 1; // high bit to sib index field
4769 rex_r = (rex & 0x4) >> 2; // high bit to modrm reg field
4770 }
4771
4772 // Analyze what we can of the opcode
4773 switch (opcode)
4774 {
4775 case 0xff:
4776 {
4777 BYTE modrm = *ip++;
4778
4779 _ASSERT(modrm != NULL);
4780
4781 BYTE mod = (modrm & 0xC0) >> 6;
4782 BYTE reg = (modrm & 0x38) >> 3;
4783 BYTE rm = (modrm & 0x07);
4784
4785 reg |= (rex_r << 3);
4786 rm |= (rex_b << 3);
4787
4788 if ((reg < 2) || (reg > 5 && reg < 8) || (reg > 15)) {
4789 // not a valid register for a CALL or BRANCH
4790 _ASSERTE(!"Invalid opcode!");
4791 return -1;
4792 }
4793
4794 WORD displace = -1;
4795
4796 // See: Tables A-15,16,17 in AMD Dev Manual 3 for information
4797 // about how the ModRM/SIB/REX bytes interact.
4798
4799 switch (mod)
4800 {
4801 case 0:
4802 case 1:
4803 case 2:
4804 if ((rm & 0x07) == 4) // we have an SIB byte following
4805 {
4806 //
4807 // Get values from the SIB byte
4808 //
4809 BYTE sib = *ip;
4810 _ASSERT(sib != NULL);
4811
4812 BYTE base = (sib & 0x07);
4813 base |= (rex_b << 3);
4814
4815 ip++;
4816
4817 //
4818 // Finally add in the offset
4819 //
4820 if (mod == 0)
4821 {
4822 if ((base & 0x07) == 5)
4823 displace = 7;
4824 else
4825 displace = 3;
4826 }
4827 else if (mod == 1)
4828 {
4829 displace = 4;
4830 }
4831 else // mod == 2
4832 {
4833 displace = 7;
4834 }
4835 }
4836 else
4837 {
4838 //
4839 // Get the value we need from the register.
4840 //
4841
4842 // Check for RIP-relative addressing mode.
4843 if ((mod == 0) && ((rm & 0x07) == 5))
4844 {
4845 displace = 6; // 1 byte opcode + 1 byte modrm + 4 byte displacement (signed)
4846 }
4847 else
4848 {
4849 if (mod == 0)
4850 displace = 2;
4851 else if (mod == 1)
4852 displace = 3;
4853 else // mod == 2
4854 displace = 6;
4855 }
4856 }
4857
4858 break;
4859
4860 case 3:
4861 default:
4862 displace = 2;
4863 }
4864
4865 // Displace should be set by one of the cases above
4866 if (displace == -1)
4867 {
4868 _ASSERTE(!"GetCallInstructionLength() encountered unexpected call instruction");
4869 return -1;
4870 }
4871
4872 // Account for the 1 byte prefix (REX or otherwise)
4873 if (fContainsPrefix)
4874 displace++;
4875
4876 // reg == 4 or 5 means that it is not a CALL, but JMP instruction
4877 // so we will fall back to ASSERT after break
4878 if ((reg != 4) && (reg != 5))
4879 return displace;
4880 break;
4881 }
4882 case 0xe8:
4883 {
4884 //Near call with the target specified by a 32-bit relative displacement.
4885 //[maybe 1 byte prefix] + [1 byte opcode E8h] + [4 bytes offset]
4886 return 5 + (fContainsPrefix ? 1 : 0);
4887 }
4888 default:
4889 break;
4890 }
4891
4892 _ASSERTE(!"Invalid opcode!");
4893 return -1;
4894#else
4895#error Platform not implemented
4896#endif
4897}
4898
4899HRESULT CordbNativeCode::GetSigParserFromFunction(mdToken mdFunction, mdToken *pClass, SigParser &parser, SigParser &methodGenerics)
4900{
4901 // mdFunction may be a MemberRef, a MethodDef, or a MethodSpec. We must handle all three cases.
4902 HRESULT hr = S_OK;
4903 IMetaDataImport* pImport = m_pFunction->GetModule()->GetMetaDataImporter();
4904 RSExtSmartPtr<IMetaDataImport2> pImport2;
4905 IfFailRet(pImport->QueryInterface(IID_IMetaDataImport2, (void**)&pImport2));
4906
4907 if (TypeFromToken(mdFunction) == mdtMemberRef)
4908 {
4909 PCCOR_SIGNATURE sig = 0;
4910 ULONG sigSize = 0;
4911 IfFailRet(pImport->GetMemberRefProps(mdFunction, pClass, NULL, 0, 0, &sig, &sigSize));
4912 parser = SigParser(sig, sigSize);
4913 }
4914 else if (TypeFromToken(mdFunction) == mdtMethodDef)
4915 {
4916 PCCOR_SIGNATURE sig = 0;
4917 ULONG sigSize = 0;
4918 IfFailRet(pImport->GetMethodProps(mdFunction, pClass, NULL, 0, NULL, NULL, &sig, &sigSize, NULL, NULL));
4919 parser = SigParser(sig, sigSize);
4920 }
4921 else if (TypeFromToken(mdFunction) == mdtMethodSpec)
4922 {
4923 // For a method spec, we use GetMethodSpecProps to get the generic singature and the parent token
4924 // (which is a MethodDef token). We'll recurse to get the other properties from the parent token.
4925
4926 PCCOR_SIGNATURE sig = 0;
4927 ULONG sigSize = 0;
4928 mdToken parentToken = 0;
4929 IfFailRet(pImport2->GetMethodSpecProps(mdFunction, &parentToken, &sig, &sigSize));
4930 methodGenerics = SigParser(sig, sigSize);
4931
4932 if (pClass)
4933 *pClass = parentToken;
4934
4935 return GetSigParserFromFunction(parentToken, pClass, parser, methodGenerics);
4936 }
4937 else
4938 {
4939 // According to ECMA III.3.19, this can never happen.
4940 return E_UNEXPECTED;
4941 }
4942
4943 return S_OK;
4944}
4945
4946HRESULT CordbNativeCode::EnsureReturnValueAllowed(Instantiation *currentInstantiation, mdToken targetClass, SigParser &parser, SigParser &methodGenerics)
4947{
4948 HRESULT hr = S_OK;
4949 ULONG genCount = 0;
4950 IfFailRet(SkipToReturn(parser, &genCount));
4951
4952 return EnsureReturnValueAllowedWorker(currentInstantiation, targetClass, parser, methodGenerics, genCount);
4953}
4954
4955HRESULT CordbNativeCode::EnsureReturnValueAllowedWorker(Instantiation *currentInstantiation, mdToken targetClass, SigParser &parser, SigParser &methodGenerics, ULONG genCount)
4956{
4957 // There are a few considerations here:
4958 // 1. Generic instantiations. This is a "Foo<T>", and we need to check if that "Foo"
4959 // fits one of the categories we disallow (such as a struct).
4960 // 2. Void return.
4961 // 3. ValueType - Unsupported this release.
4962 // 4. MVAR - Method generics. We need to get the actual generic type and recursively
4963 // check if we allow that.
4964 // 5. VAR - Class generics. We need to get the actual generic type and recurse.
4965
4966 SigParser original(parser);
4967 HRESULT hr = S_OK;
4968 CorElementType returnType;
4969 IfFailRet(parser.GetElemType(&returnType));
4970 if (returnType == ELEMENT_TYPE_GENERICINST)
4971 {
4972 IfFailRet(parser.GetElemType(&returnType));
4973
4974 if (returnType == ELEMENT_TYPE_CLASS)
4975 return S_OK;
4976
4977 if (returnType != ELEMENT_TYPE_VALUETYPE)
4978 return META_E_BAD_SIGNATURE;
4979
4980 if (currentInstantiation == NULL)
4981 return S_OK; // We will check again when we have the instantiation.
4982
4983 NewArrayHolder<CordbType*> types;
4984 Instantiation inst;
4985 IfFailRet(CordbJITILFrame::BuildInstantiationForCallsite(GetModule(), types, inst, currentInstantiation, targetClass, SigParser(methodGenerics)));
4986
4987 CordbType *pType = 0;
4988 IfFailRet(CordbType::SigToType(GetModule(), &original, &inst, &pType));
4989
4990
4991 IfFailRet(hr = pType->ReturnedByValue());
4992 if (hr == S_OK) // not S_FALSE
4993 return S_OK;
4994
4995 return CORDBG_E_UNSUPPORTED;
4996 }
4997
4998 if (returnType == ELEMENT_TYPE_VALUETYPE)
4999 {
5000 Instantiation inst;
5001 CordbType *pType = 0;
5002 IfFailRet(CordbType::SigToType(GetModule(), &original, &inst, &pType));
5003
5004 IfFailRet(hr = pType->ReturnedByValue());
5005 if (hr == S_OK) // not S_FALSE
5006 return S_OK;
5007
5008 return CORDBG_E_UNSUPPORTED;
5009 }
5010
5011 if (returnType == ELEMENT_TYPE_TYPEDBYREF)
5012 return CORDBG_E_UNSUPPORTED;
5013
5014 if (returnType == ELEMENT_TYPE_VOID)
5015 return E_UNEXPECTED;
5016
5017 if (returnType == ELEMENT_TYPE_MVAR)
5018 {
5019 // Get which generic parameter is referenced.
5020 ULONG genParam = 0;
5021 IfFailRet(parser.GetData(&genParam));
5022
5023 // Grab the calling convention of the method, ensure it's GENERICINST.
5024 ULONG callingConv = 0;
5025 IfFailRet(methodGenerics.GetCallingConvInfo(&callingConv));
5026 if (callingConv != IMAGE_CEE_CS_CALLCONV_GENERICINST)
5027 return META_E_BAD_SIGNATURE;
5028
5029 // Ensure sensible bounds.
5030 SigParser generics(methodGenerics); // Make a copy since operations are destructive.
5031 ULONG maxCount = 0;
5032 IfFailRet(generics.GetData(&maxCount));
5033 if (maxCount <= genParam || genParam > 1024)
5034 return META_E_BAD_SIGNATURE;
5035
5036 // Walk to the parameter referenced.
5037 while (genParam--)
5038 IfFailRet(generics.SkipExactlyOne());
5039
5040 // Now recurse with "generics" at the location to continue parsing.
5041 return EnsureReturnValueAllowedWorker(currentInstantiation, targetClass, generics, methodGenerics, genCount);
5042 }
5043
5044
5045 if (returnType == ELEMENT_TYPE_VAR)
5046 {
5047 // Get which type parameter is reference.
5048 ULONG typeParam = 0;
5049 parser.GetData(&typeParam);
5050
5051 // Ensure something reasonable.
5052 if (typeParam > 1024)
5053 return META_E_BAD_SIGNATURE;
5054
5055 // Lookup the containing class's signature so we can get the referenced generic parameter.
5056 IMetaDataImport *pImport = m_pFunction->GetModule()->GetMetaDataImporter();
5057 PCCOR_SIGNATURE sig;
5058 ULONG countSig;
5059 IfFailRet(pImport->GetTypeSpecFromToken(targetClass, &sig, &countSig));
5060
5061 // Enusre the type's typespec is GENERICINST.
5062 SigParser typeParser(sig, countSig);
5063 CorElementType et;
5064 IfFailRet(typeParser.GetElemType(&et));
5065 if (et != ELEMENT_TYPE_GENERICINST)
5066 return META_E_BAD_SIGNATURE;
5067
5068 // Move to the correct location.
5069 IfFailRet(typeParser.GetElemType(&et));
5070 if (et != ELEMENT_TYPE_VALUETYPE && et != ELEMENT_TYPE_CLASS)
5071 return META_E_BAD_SIGNATURE;
5072
5073 IfFailRet(typeParser.GetToken(NULL));
5074
5075 ULONG totalTypeCount = 0;
5076 IfFailRet(typeParser.GetData(&totalTypeCount));
5077 if (totalTypeCount < typeParam)
5078 return META_E_BAD_SIGNATURE;
5079
5080 while (typeParam--)
5081 IfFailRet(typeParser.SkipExactlyOne());
5082
5083 // This is a temporary workaround for an infinite recursion here. ALL of this code will
5084 // go away when we allow struct return values, but in the mean time this avoids a corner
5085 // case in the type system we haven't solved yet.
5086 IfFailRet(typeParser.PeekElemType(&et));
5087 if (et == ELEMENT_TYPE_VAR)
5088 return E_FAIL;
5089
5090 // Now that typeParser is at the location of the correct generic parameter, recurse.
5091 return EnsureReturnValueAllowedWorker(currentInstantiation, targetClass, typeParser, methodGenerics, genCount);
5092 }
5093
5094 // Everything else supported
5095 return S_OK;
5096}
5097
5098HRESULT CordbNativeCode::SkipToReturn(SigParser &parser, ULONG *genCount)
5099{
5100 // Takes a method signature parser (at the beginning of a signature) and skips to the
5101 // return value.
5102 HRESULT hr = S_OK;
5103
5104 // Skip calling convention
5105 ULONG uCallConv;
5106 IfFailRet(parser.GetCallingConvInfo(&uCallConv));
5107 if ((uCallConv == IMAGE_CEE_CS_CALLCONV_FIELD) || (uCallConv == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG))
5108 return META_E_BAD_SIGNATURE;
5109
5110 // Skip type parameter count if function is generic
5111 if (uCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
5112 IfFailRet(parser.GetData(genCount));
5113
5114 // Skip argument count
5115 IfFailRet(parser.GetData(NULL));
5116
5117 return S_OK;
5118}
5119
5120HRESULT CordbNativeCode::GetCallSignature(ULONG32 ILoffset, mdToken *pClass, mdToken *pFunction, SigParser &parser, SigParser &generics)
5121{
5122 // check if specified IL offset is at a call instruction
5123 CordbILCode *pCode = this->m_pFunction->GetILCode();
5124 BYTE buffer[3];
5125 ULONG32 fetched = 0;
5126 HRESULT hr = pCode->GetCode(ILoffset, ILoffset+_countof(buffer), _countof(buffer), buffer, &fetched);
5127
5128 if (FAILED(hr))
5129 return hr;
5130 else if (fetched != _countof(buffer))
5131 return CORDBG_E_INVALID_OPCODE;
5132
5133 // tail. - fe 14 (ECMA III.2.4)
5134 BYTE instruction = buffer[0];
5135 if (buffer[0] == 0xfe && buffer[1] == 0x14)
5136 {
5137 // tail call case. We don't allow managed return values for tailcalls.
5138 return CORDBG_E_INVALID_OPCODE;
5139 }
5140
5141 // call - 28 (ECMA III.3.19)
5142 // callvirt - 6f (ECMA III.4.2)
5143 if (instruction != 0x28 && instruction != 0x6f)
5144 return CORDBG_E_INVALID_OPCODE;
5145
5146 // Now grab the MD token of the call
5147 mdToken mdFunction = 0;
5148 const ULONG32 offset = ILoffset + 1;
5149 hr = pCode->GetCode(offset, offset+sizeof(mdToken), sizeof(mdToken), (BYTE*)&mdFunction, &fetched);
5150 if (FAILED(hr) || fetched != sizeof(mdToken))
5151 return CORDBG_E_INVALID_OPCODE;
5152
5153 if (pFunction)
5154 *pFunction = mdFunction;
5155
5156 // Convert to a signature parser
5157 return GetSigParserFromFunction(mdFunction, pClass, parser, generics);
5158}
5159
5160HRESULT CordbNativeCode::GetReturnValueLiveOffsetImpl(Instantiation *currentInstantiation, ULONG32 ILoffset, ULONG32 bufferSize, ULONG32 *pFetched, ULONG32 *pOffsets)
5161{
5162 if (pFetched == NULL)
5163 return E_INVALIDARG;
5164
5165 HRESULT hr = S_OK;
5166 ULONG32 found = 0;
5167
5168 // verify that the call target actually returns something we allow
5169 SigParser signature, generics;
5170 mdToken mdClass = 0;
5171 IfFailRet(GetCallSignature(ILoffset, &mdClass, NULL, signature, generics));
5172 IfFailRet(EnsureReturnValueAllowed(currentInstantiation, mdClass, signature, generics));
5173
5174 // now find the native offset
5175 SequencePoints *pSP = GetSequencePoints();
5176 DebuggerILToNativeMap *pMap = pSP->GetCallsiteMapAddr();
5177
5178 for (ULONG32 i = 0; i < pSP->GetCallsiteEntryCount() && pMap; ++i, pMap++)
5179 {
5180 if (pMap->ilOffset == ILoffset && (pMap->source & ICorDebugInfo::CALL_INSTRUCTION) == ICorDebugInfo::CALL_INSTRUCTION)
5181 {
5182 // if we have a buffer, fill it in.
5183 if (pOffsets && found < bufferSize)
5184 {
5185 // Fetch the actual assembly instructions
5186 BYTE nativeBuffer[8];
5187
5188 ULONG32 fetched = 0;
5189 IfFailRet(GetCode(pMap->nativeStartOffset, pMap->nativeStartOffset+_countof(nativeBuffer), _countof(nativeBuffer), nativeBuffer, &fetched));
5190
5191 int skipBytes = 0;
5192
5193#if defined(DBG_TARGET_X86) && defined(FEATURE_CORESYSTEM)
5194 // Skip nop sleds on x86 coresystem. The JIT adds these instructions as a security measure,
5195 // and incorrectly reports to us the wrong offset of the call instruction.
5196 const BYTE nop_opcode = 0x90;
5197 while (fetched && nativeBuffer[0] == nop_opcode)
5198 {
5199 skipBytes++;
5200
5201 for (int j = 1; j < _countof(nativeBuffer) && nativeBuffer[j] == nop_opcode; ++j)
5202 skipBytes++;
5203
5204 // We must have at least one skip byte since the outer while ensures it. Thus we always need to reread
5205 // the buffer at the end of this loop.
5206 IfFailRet(GetCode(pMap->nativeStartOffset+skipBytes, pMap->nativeStartOffset+skipBytes+_countof(nativeBuffer), _countof(nativeBuffer), nativeBuffer, &fetched));
5207 }
5208#endif
5209
5210 // Get the length of the call instruction.
5211 int offset = GetCallInstructionLength(nativeBuffer, fetched);
5212 if (offset == -1)
5213 return E_UNEXPECTED; // Could not decode instruction, this should never happen.
5214
5215 pOffsets[found] = pMap->nativeStartOffset + offset + skipBytes;
5216 }
5217
5218 found++;
5219 }
5220 }
5221
5222 if (pOffsets)
5223 *pFetched = found < bufferSize ? found : bufferSize;
5224 else
5225 *pFetched = found;
5226
5227 if (found == 0)
5228 return E_FAIL;
5229
5230 if (pOffsets && found > bufferSize)
5231 return S_FALSE;
5232
5233 return S_OK;
5234}
5235
5236//-----------------------------------------------------------------------------
5237// Creates a CordbNativeCode (if it's not already created) and adds it to the
5238// hash table of CordbNativeCode instances belonging to this module.
5239// Used by CordbFunction::InitNativeCodeInfo.
5240//
5241// Arguments:
5242// Input:
5243// methodToken - the methodDef token of the function this native code belongs to
5244// methodDesc - the methodDesc for the jitted method
5245// startAddress - the hot code startAddress for this method
5246
5247// Return value:
5248// found or created CordbNativeCode pointer
5249// Assumptions: methodToken is in the metadata for this module
5250// methodDesc and startAddress should be consistent for
5251// a jitted instance of methodToken's method
5252//-----------------------------------------------------------------------------
5253CordbNativeCode * CordbModule::LookupOrCreateNativeCode(mdMethodDef methodToken,
5254 VMPTR_MethodDesc methodDesc,
5255 CORDB_ADDRESS startAddress)
5256{
5257 INTERNAL_SYNC_API_ENTRY(GetProcess());
5258 _ASSERTE(startAddress != NULL);
5259 _ASSERTE(methodDesc != VMPTR_MethodDesc::NullPtr());
5260
5261 CordbNativeCode * pNativeCode = NULL;
5262 NativeCodeFunctionData codeInfo;
5263 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
5264
5265 // see if we already have this--if not, we'll make an instance, otherwise we'll just return the one we have.
5266 pNativeCode = m_nativeCodeTable.GetBase((UINT_PTR) startAddress);
5267
5268 if (pNativeCode == NULL)
5269 {
5270 GetProcess()->GetDAC()->GetNativeCodeInfoForAddr(methodDesc, startAddress, &codeInfo);
5271
5272 // We didn't have an instance, so we'll build one and add it to the hash table
5273 LOG((LF_CORDB,
5274 LL_INFO10000,
5275 "R:CT::RSCreating code w/ ver:0x%x, md:0x%x, nativeStart=0x%08x, nativeSize=0x%08x\n",
5276 codeInfo.encVersion,
5277 VmPtrToCookie(codeInfo.vmNativeCodeMethodDescToken),
5278 codeInfo.m_rgCodeRegions[kHot].pAddress,
5279 codeInfo.m_rgCodeRegions[kHot].cbSize));
5280
5281 // Lookup the function object that this code should be bound to
5282 CordbFunction* pFunction = CordbModule::LookupOrCreateFunction(methodToken, codeInfo.encVersion);
5283 _ASSERTE(pFunction != NULL);
5284
5285 // There are bugs with the on-demand class load performed by CordbFunction in some cases. The old stack
5286 // tracing code avoided them by eagerly loading the parent class so I am following suit
5287 pFunction->InitParentClassOfFunction();
5288
5289 // First, create a new CordbNativeCode instance--we'll need this to make the CordbJITInfo instance
5290 pNativeCode = new (nothrow)CordbNativeCode(pFunction, &codeInfo, codeInfo.isInstantiatedGeneric != 0);
5291 _ASSERTE(pNativeCode != NULL);
5292
5293 m_nativeCodeTable.AddBaseOrThrow(pNativeCode);
5294 }
5295
5296 return pNativeCode;
5297} // CordbNativeCode::LookupOrCreateFromJITData
5298
5299// LoadNativeInfo loads from the left side any native variable info
5300// from the JIT.
5301//
5302void CordbNativeCode::LoadNativeInfo()
5303{
5304 THROW_IF_NEUTERED(this);
5305 INTERNAL_API_ENTRY(this->GetProcess());
5306
5307
5308 // If we've either never done this before (no info), or we have, but the version number has increased, we
5309 // should try and get a newer version of our JIT info.
5310 if(m_nativeVarData.IsInitialized())
5311 {
5312 return;
5313 }
5314
5315 // You can't do this if the function is implemented as part of the Runtime.
5316 if (GetFunction()->IsNativeImpl() == CordbFunction::kNativeOnly)
5317 {
5318 ThrowHR(CORDBG_E_FUNCTION_NOT_IL);
5319 }
5320 CordbProcess *pProcess = GetProcess();
5321 // Get everything via the DAC
5322 if (m_fCodeAvailable)
5323 {
5324 RSLockHolder lockHolder(pProcess->GetProcessLock());
5325 pProcess->GetDAC()->GetNativeCodeSequencePointsAndVarInfo(GetVMNativeCodeMethodDescToken(),
5326 GetAddress(),
5327 m_fCodeAvailable,
5328 &m_nativeVarData,
5329 &m_sequencePoints);
5330 }
5331
5332} // CordbNativeCode::LoadNativeInfo
5333
5334
5335
5336