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 | // File: rsfunction.cpp |
6 | // |
7 | |
8 | // |
9 | //***************************************************************************** |
10 | #include "stdafx.h" |
11 | |
12 | // We have an assert in ceemain.cpp that validates this assumption |
13 | #define FIELD_OFFSET_NEW_ENC_DB 0x07FFFFFB |
14 | |
15 | #include "winbase.h" |
16 | #include "corpriv.h" |
17 | |
18 | /* ------------------------------------------------------------------------- * |
19 | * Function class |
20 | * ------------------------------------------------------------------------- */ |
21 | |
22 | //----------------------------------------------------------------------------- |
23 | // Constructor for CordbFunction class. |
24 | // This represents an IL Function in the debuggee. |
25 | // CordbFunction is 1:1 with IL method bodies. |
26 | // |
27 | // Parameters: |
28 | // m - module containing this function. All functions live in a single module. |
29 | // funcMetadataToken - the metadata token for this function (scoped to the module). |
30 | // enCVersion - Enc Version number of this function (in sync with the module's |
31 | // EnC version). Each edit to a function means a whole new IL method body, |
32 | // and since CordbFunction is 1:1 with IL, that means a new CordbFunction instance. |
33 | //----------------------------------------------------------------------------- |
34 | CordbFunction::CordbFunction(CordbModule * m, |
35 | mdMethodDef funcMetadataToken, |
36 | SIZE_T enCVersion) |
37 | : CordbBase(m->GetProcess(), funcMetadataToken, enumCordbFunction), m_pModule(m), m_pClass(NULL), |
38 | m_pILCode(NULL), |
39 | m_nativeCode(NULL), |
40 | m_MDToken(funcMetadataToken), |
41 | m_dwEnCVersionNumber(enCVersion), |
42 | m_pPrevVersion(NULL), |
43 | m_fIsNativeImpl(kUnknownImpl), |
44 | m_fCachedMethodValuesValid(FALSE), |
45 | m_argCountCached(0), |
46 | m_fIsStaticCached(FALSE), |
47 | m_reJitILCodes(1) |
48 | { |
49 | m_methodSigParserCached = SigParser(NULL, 0); |
50 | |
51 | _ASSERTE(enCVersion >= CorDB_DEFAULT_ENC_FUNCTION_VERSION); |
52 | } |
53 | |
54 | |
55 | |
56 | /* |
57 | A list of which resources owned by this object are accounted for. |
58 | |
59 | UNKNOWN: |
60 | ICorDebugInfo::NativeVarInfo *m_nativeInfo; |
61 | |
62 | HANDLED: |
63 | CordbModule *m_module; // Assigned w/o AddRef() |
64 | CordbClass *m_class; // Assigned w/o AddRef() |
65 | */ |
66 | |
67 | //----------------------------------------------------------------------------- |
68 | // CordbFunction destructor |
69 | // All external resources, including references counts, should have been |
70 | // released in Neuter(), so this should literally just delete memory or |
71 | // or check that the object is already dead. |
72 | //----------------------------------------------------------------------------- |
73 | CordbFunction::~CordbFunction() |
74 | { |
75 | // We should have been explicitly neutered before our internal ref went to 0. |
76 | _ASSERTE(IsNeutered()); |
77 | |
78 | // Since we've been neutered, we shouldn't have any References to release and |
79 | // our hash of JitInfos should be empty. |
80 | _ASSERTE(m_pILCode == NULL); |
81 | _ASSERTE(m_pPrevVersion == NULL); |
82 | } |
83 | |
84 | //----------------------------------------------------------------------------- |
85 | // CordbFunction::Neuter |
86 | // Neuter releases all of the resources this object holds. CordbFunction |
87 | // lives in a CordbModule, so Module neuter will neuter this. |
88 | // See CordbBase::Neuter for further semantics. |
89 | // |
90 | //----------------------------------------------------------------------------- |
91 | void CordbFunction::Neuter() |
92 | { |
93 | // Neuter any/all CordbNativeCode & CordbILCode objects |
94 | if (m_pILCode != NULL) |
95 | { |
96 | m_pILCode->Neuter(); |
97 | m_pILCode.Clear(); // this will internal release. |
98 | } |
99 | |
100 | // Neuter & Release the Prev-Function list. |
101 | if (m_pPrevVersion != NULL) |
102 | { |
103 | m_pPrevVersion->Neuter(); |
104 | m_pPrevVersion.Clear(); // this will internal release. |
105 | } |
106 | |
107 | m_pModule = NULL; |
108 | m_pClass = NULL; |
109 | |
110 | m_nativeCode.Clear(); |
111 | m_reJitILCodes.NeuterAndClear(GetProcess()->GetProcessLock()); |
112 | |
113 | CordbBase::Neuter(); |
114 | } |
115 | |
116 | //----------------------------------------------------------------------------- |
117 | // CordbFunction::QueryInterface |
118 | // Public method to implement IUnknown::QueryInterface. |
119 | // Has standard QI semantics. |
120 | //----------------------------------------------------------------------------- |
121 | HRESULT CordbFunction::QueryInterface(REFIID id, void **pInterface) |
122 | { |
123 | if (id == IID_ICorDebugFunction) |
124 | { |
125 | *pInterface = static_cast<ICorDebugFunction*>(this); |
126 | } |
127 | else if (id == IID_ICorDebugFunction2) |
128 | { |
129 | *pInterface = static_cast<ICorDebugFunction2*>(this); |
130 | } |
131 | else if (id == IID_ICorDebugFunction3) |
132 | { |
133 | *pInterface = static_cast<ICorDebugFunction3*>(this); |
134 | } |
135 | else if (id == IID_ICorDebugFunction4) |
136 | { |
137 | *pInterface = static_cast<ICorDebugFunction4*>(this); |
138 | } |
139 | else if (id == IID_IUnknown) |
140 | { |
141 | *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugFunction*>(this)); |
142 | } |
143 | else |
144 | { |
145 | *pInterface = NULL; |
146 | return E_NOINTERFACE; |
147 | } |
148 | |
149 | ExternalAddRef(); |
150 | return S_OK; |
151 | } |
152 | |
153 | //----------------------------------------------------------------------------- |
154 | // CordbFunction::GetModule |
155 | // Public method (implements ICorDebugFunction::GetModule). |
156 | // Get the ICorDebugModule (external representation of a module) that this |
157 | // Function is contained in. All functions live in exactly 1 module. |
158 | // This is related to the 'CordbModule* GetModule()' method which returns the |
159 | // internal module representation for the containing module. |
160 | // |
161 | // Parameters: |
162 | // ppModule - out parameter to hold module. |
163 | // |
164 | // Return values: |
165 | // S_OK iff *ppModule is set. |
166 | //----------------------------------------------------------------------------- |
167 | HRESULT CordbFunction::GetModule(ICorDebugModule **ppModule) |
168 | { |
169 | PUBLIC_API_ENTRY(this); |
170 | FAIL_IF_NEUTERED(this); |
171 | VALIDATE_POINTER_TO_OBJECT(ppModule, ICorDebugModule **); |
172 | |
173 | HRESULT hr = S_OK; |
174 | |
175 | // Module is set on creation, so just return it. |
176 | *ppModule = static_cast<ICorDebugModule*> (m_pModule); |
177 | m_pModule->ExternalAddRef(); |
178 | |
179 | return hr; |
180 | } |
181 | |
182 | //----------------------------------------------------------------------------- |
183 | // CordbFunction::GetClass |
184 | // Public function to get ICorDebugClass that this function is in. |
185 | // |
186 | // Parameters: |
187 | // ppClass - out parameter holding which class this function lives in. |
188 | // |
189 | // Return value: |
190 | // S_OK iff *ppClass is set. |
191 | //----------------------------------------------------------------------------- |
192 | HRESULT CordbFunction::GetClass(ICorDebugClass **ppClass) |
193 | { |
194 | PUBLIC_API_ENTRY(this); |
195 | FAIL_IF_NEUTERED(this); |
196 | VALIDATE_POINTER_TO_OBJECT(ppClass, ICorDebugClass **); |
197 | ATT_ALLOW_LIVE_DO_STOPGO(GetProcess()); |
198 | *ppClass = NULL; |
199 | |
200 | HRESULT hr = S_OK; |
201 | |
202 | if (m_pClass == NULL) |
203 | { |
204 | // We're not looking for any particular version, just |
205 | // the class info. This seems like the best version to request |
206 | hr = InitParentClassOfFunction(); |
207 | |
208 | if (FAILED(hr)) |
209 | goto LExit; |
210 | } |
211 | |
212 | *ppClass = static_cast<ICorDebugClass*> (m_pClass); |
213 | |
214 | LExit: |
215 | if (FAILED(hr)) |
216 | return hr; |
217 | |
218 | if (*ppClass) |
219 | { |
220 | m_pClass->ExternalAddRef(); |
221 | return S_OK; |
222 | } |
223 | else |
224 | return S_FALSE; |
225 | } |
226 | |
227 | //----------------------------------------------------------------------------- |
228 | // CordbFunction::GetToken |
229 | // Public function to get the metadata token for this function. |
230 | // This is a MethodDef, which is scoped to a module. |
231 | // |
232 | // Parameters: |
233 | // pMemberDef - out parameter to hold token. |
234 | // |
235 | // Return values: |
236 | // S_OK if pMemberDef is set. |
237 | //----------------------------------------------------------------------------- |
238 | HRESULT CordbFunction::GetToken(mdMethodDef *pMemberDef) |
239 | { |
240 | PUBLIC_API_ENTRY(this); |
241 | FAIL_IF_NEUTERED(this); |
242 | VALIDATE_POINTER_TO_OBJECT(pMemberDef, mdMethodDef *); |
243 | |
244 | |
245 | // Token is set on creation, so no updating needed. |
246 | CONSISTENCY_CHECK_MSGF((TypeFromToken(m_MDToken) == mdtMethodDef), |
247 | ("CordbFunction token (%08x) is not a mdtMethodDef. This=%p" , m_MDToken, this)); |
248 | |
249 | *pMemberDef = m_MDToken; |
250 | return S_OK; |
251 | } |
252 | |
253 | //----------------------------------------------------------------------------- |
254 | // CordbFunction::GetILCode |
255 | // Public function to get an ICorDebugCode object for the IL code in |
256 | // this function. |
257 | // If we EnC, we get a new ICorDebugFunction, so the IL code & function |
258 | // should be 1:1. |
259 | // |
260 | // Parameters: |
261 | // ppCode - out parameter to hold the code object. |
262 | // |
263 | // Return value: |
264 | // S_OK iff *ppCode != NULL. Else error. |
265 | //----------------------------------------------------------------------------- |
266 | HRESULT CordbFunction::GetILCode(ICorDebugCode ** ppCode) |
267 | { |
268 | PUBLIC_REENTRANT_API_ENTRY(this); |
269 | FAIL_IF_NEUTERED(this); |
270 | VALIDATE_POINTER_TO_OBJECT(ppCode, ICorDebugCode **); |
271 | ATT_ALLOW_LIVE_DO_STOPGO(GetProcess()); |
272 | |
273 | *ppCode = NULL; |
274 | HRESULT hr = S_OK; |
275 | |
276 | // Get the code object. |
277 | CordbILCode * pCode = NULL; |
278 | hr = GetILCode(&pCode); |
279 | _ASSERTE((pCode == NULL) == FAILED(hr)); |
280 | |
281 | if (FAILED(hr)) |
282 | return hr; |
283 | |
284 | *ppCode = (ICorDebugCode *)pCode; |
285 | |
286 | return hr; |
287 | } |
288 | |
289 | //----------------------------------------------------------------------------- |
290 | // CordbFunction::GetNativeCode |
291 | // Public API (ICorDebugFunction::GetNativeCode) to get the native code for |
292 | // this function. |
293 | // Note that this gets a pretty much random version of the native code when the |
294 | // function is a generic method that gets JITted more than once, e.g. for generics. |
295 | // Use EnumerateNativeCode instead in that case. |
296 | // |
297 | // Parameters: |
298 | // ppCode - out parameter yeilding the native code object. |
299 | // |
300 | // Returns: |
301 | // S_OK iff *ppCode is set. |
302 | // CORDBG_E_CODE_NOT_AVAILABLE if there is no native code. This is common |
303 | // if the function is not yet jitted. |
304 | //----------------------------------------------------------------------------- |
305 | HRESULT CordbFunction::GetNativeCode(ICorDebugCode **ppCode) |
306 | { |
307 | PUBLIC_API_ENTRY(this); |
308 | FAIL_IF_NEUTERED(this); |
309 | VALIDATE_POINTER_TO_OBJECT(ppCode, ICorDebugCode **); |
310 | ATT_ALLOW_LIVE_DO_STOPGO(GetProcess()); |
311 | |
312 | HRESULT hr = S_OK; |
313 | |
314 | // Make sure native code is updated before we go searching it. |
315 | hr = InitNativeCodeInfo(); |
316 | if (FAILED(hr)) |
317 | return hr; |
318 | |
319 | // Generic methods may be jitted multiple times for different native instantiations, |
320 | // and so have 1:n relationship between IL:Native. CordbFunction is 1:1 with IL, |
321 | // CordbNativeCode is 1:1 with native. |
322 | // The interface here only lets us return 1 CordbNativeCode object, so we are |
323 | // returning an arbitrary one |
324 | RSLockHolder lockHolder(GetProcess()->GetProcessLock()); |
325 | _ASSERTE(m_nativeCode == NULL || m_nativeCode->GetVersion() == m_dwEnCVersionNumber); |
326 | |
327 | if (m_nativeCode == NULL) |
328 | { |
329 | hr = CORDBG_E_CODE_NOT_AVAILABLE; // This is the case for an unjitted function, |
330 | // and so it will be very common. |
331 | } |
332 | else |
333 | { |
334 | m_nativeCode->ExternalAddRef(); |
335 | *ppCode = m_nativeCode; |
336 | hr = S_OK; |
337 | } |
338 | |
339 | return hr; |
340 | } |
341 | |
342 | |
343 | //----------------------------------------------------------------------------- |
344 | // CordbFunction::GetCode |
345 | // Internal method to get the IL code for this function. Each CordbFunction is |
346 | // 1:1 with IL, so there is a unique IL Code object to hand out. |
347 | // |
348 | // Parameters: |
349 | // ppCode - out parameter, the IL code object for this function. This should |
350 | // be set to NULL on entry. |
351 | // Return value: |
352 | // S_OK iff *ppCode is set. Else error. |
353 | //----------------------------------------------------------------------------- |
354 | HRESULT CordbFunction::GetILCode(CordbILCode ** ppCode) |
355 | { |
356 | FAIL_IF_NEUTERED(this); |
357 | INTERNAL_SYNC_API_ENTRY(GetProcess()); // |
358 | VALIDATE_POINTER_TO_OBJECT(ppCode, ICorDebugCode **); |
359 | |
360 | _ASSERTE(*ppCode == NULL && "Common source of errors is getting addref'd copy here and never Release()ing it" ); |
361 | *ppCode = NULL; |
362 | |
363 | // Its okay to do this if the process is not sync'd. |
364 | CORDBRequireProcessStateOK(GetProcess()); |
365 | |
366 | // Fetch all information about this function. |
367 | HRESULT hr = S_OK; |
368 | CordbILCode * pCode = NULL; |
369 | |
370 | hr = GetILCodeAndSigToken(); |
371 | if (FAILED(hr)) |
372 | { |
373 | return hr; |
374 | } |
375 | |
376 | // It's possible that m_ILCode will still be NULL. |
377 | pCode = m_pILCode; |
378 | |
379 | if (pCode != NULL) |
380 | { |
381 | pCode->ExternalAddRef(); |
382 | *ppCode = pCode; |
383 | |
384 | return hr; |
385 | } |
386 | else |
387 | { |
388 | return CORDBG_E_CODE_NOT_AVAILABLE; |
389 | } |
390 | } // CordbFunction::GetCode |
391 | |
392 | //----------------------------------------------------------------------------- |
393 | // CordbFunction::CreateBreakpoint |
394 | // Implements ICorDebugFunction::CreateBreakpoint |
395 | // Creates a breakpoint at IL offset 0 (which is after the prolog) of the function. |
396 | // The function does not need to be jitted yet. |
397 | // |
398 | // Parameters: |
399 | // ppBreakpoint - out parameter for newly created breakpoint object. |
400 | // |
401 | // Return: |
402 | // S_OK - on success. Else error. |
403 | //---------------------------------------------------------------------------- |
404 | HRESULT CordbFunction::CreateBreakpoint(ICorDebugFunctionBreakpoint **ppBreakpoint) |
405 | { |
406 | HRESULT hr = S_OK; |
407 | |
408 | PUBLIC_API_ENTRY(this); |
409 | FAIL_IF_NEUTERED(this); |
410 | VALIDATE_POINTER_TO_OBJECT(ppBreakpoint, ICorDebugFunctionBreakpoint **); |
411 | ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); |
412 | |
413 | RSExtSmartPtr<ICorDebugCode> pCode; |
414 | |
415 | // Use the IL code so that we stop after the prolog |
416 | hr = GetILCode(&pCode); |
417 | |
418 | if (SUCCEEDED(hr)) |
419 | { |
420 | hr = pCode->CreateBreakpoint(0, ppBreakpoint); |
421 | } |
422 | |
423 | return hr; |
424 | } |
425 | |
426 | #ifdef EnC_SUPPORTED |
427 | //----------------------------------------------------------------------------- |
428 | // CordbFunction::MakeOld |
429 | // Internal method to do any cleanup necessary when a Function is no longer |
430 | // the most current. |
431 | //----------------------------------------------------------------------------- |
432 | void CordbFunction::MakeOld() |
433 | { |
434 | if (m_pILCode != NULL) |
435 | { |
436 | m_pILCode->MakeOld(); |
437 | } |
438 | } |
439 | #endif |
440 | |
441 | //----------------------------------------------------------------------------- |
442 | // CordbFunction::GetLocalVarSigToken |
443 | // Public function (implements ICorDebugFunction::GetLocalVarSigToken) to |
444 | // get signature token. |
445 | // |
446 | // Parameters: |
447 | // pmdSig - out parameter to hold signature token, which is scoped to the |
448 | // function's module. |
449 | // |
450 | // Return value: |
451 | // S_OK if pmdSig is set. |
452 | //----------------------------------------------------------------------------- |
453 | HRESULT CordbFunction::GetLocalVarSigToken(mdSignature *pmdSig) |
454 | { |
455 | PUBLIC_API_ENTRY(this); |
456 | FAIL_IF_NEUTERED(this); |
457 | VALIDATE_POINTER_TO_OBJECT(pmdSig, mdSignature *); |
458 | |
459 | ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); |
460 | |
461 | // This will initialize the token. |
462 | HRESULT hr = GetILCodeAndSigToken(); |
463 | if (FAILED(hr)) |
464 | return hr; |
465 | |
466 | *pmdSig = GetILCode()->GetLocalVarSigToken(); |
467 | |
468 | return S_OK; |
469 | } |
470 | |
471 | //----------------------------------------------------------------------------- |
472 | // CordbFunction::GetCurrentVersionNumber |
473 | // Public method for ICorDebugFunction::GetCurrentVersionNumber. |
474 | // Gets the most recent (highest) EnC version number of this Function. |
475 | // See CordbModule for EnC version number semantics. |
476 | // |
477 | // Parameters |
478 | // pnCurrentVersion - out parameter to hold the version number. |
479 | // |
480 | // Returns: |
481 | // S_OK on success. |
482 | //----------------------------------------------------------------------------- |
483 | HRESULT CordbFunction::GetCurrentVersionNumber(ULONG32 *pnCurrentVersion) |
484 | { |
485 | PUBLIC_API_ENTRY(this); |
486 | FAIL_IF_NEUTERED(this); |
487 | VALIDATE_POINTER_TO_OBJECT(pnCurrentVersion, ULONG32 *); |
488 | |
489 | HRESULT hr = S_OK; |
490 | RSLockHolder lockHolder(GetProcess()->GetProcessLock()); |
491 | |
492 | // the most current version will always be the one found. |
493 | CordbFunction* curFunc = m_pModule->LookupFunctionLatestVersion(m_MDToken); |
494 | |
495 | // will always find at least ourself |
496 | PREFIX_ASSUME(curFunc != NULL); |
497 | |
498 | *pnCurrentVersion = (ULONG32)(curFunc->m_dwEnCVersionNumber); |
499 | |
500 | #ifdef EnC_SUPPORTED |
501 | _ASSERTE( *pnCurrentVersion >= this->m_dwEnCVersionNumber ); |
502 | #else |
503 | _ASSERTE(*pnCurrentVersion == CorDB_DEFAULT_ENC_FUNCTION_VERSION); |
504 | #endif |
505 | |
506 | return hr; |
507 | } |
508 | |
509 | //----------------------------------------------------------------------------- |
510 | // CordbFunction::GetVersionNumber |
511 | // Public method for ICorDebugFunction2::GetVersionNumber. |
512 | // Gets the EnC version number of this specific Function instance. |
513 | // See CordbModule for EnC version number semantics. |
514 | // |
515 | // Parameters |
516 | // pnVersion - out parameter to hold the version number. |
517 | // |
518 | // Returns: |
519 | // S_OK on success. |
520 | //----------------------------------------------------------------------------- |
521 | HRESULT CordbFunction::GetVersionNumber(ULONG32 *pnVersion) |
522 | { |
523 | PUBLIC_API_ENTRY(this); |
524 | FAIL_IF_NEUTERED(this); |
525 | VALIDATE_POINTER_TO_OBJECT(pnVersion, ULONG32 *); |
526 | |
527 | // This API existed in V1.0 but wasn't implemented. It needs V2 support to work. |
528 | if (! this->GetProcess()->SupportsVersion(ver_ICorDebugFunction2)) |
529 | { |
530 | return E_NOTIMPL; |
531 | } |
532 | |
533 | *pnVersion = (ULONG32)m_dwEnCVersionNumber; |
534 | |
535 | #ifdef EnC_SUPPORTED |
536 | _ASSERTE(*pnVersion >= CorDB_DEFAULT_ENC_FUNCTION_VERSION); |
537 | #else |
538 | _ASSERTE(*pnVersion == CorDB_DEFAULT_ENC_FUNCTION_VERSION); |
539 | #endif |
540 | |
541 | return S_OK; |
542 | } |
543 | |
544 | //----------------------------------------------------------------------------- |
545 | // CordbFunction::GetVersionNumber |
546 | // Public method for ICorDebugFunction2::GetVersionNumber. |
547 | // Gets the EnC version number of this specific Function instance. |
548 | // See CordbModule for EnC version number semantics. |
549 | // |
550 | // Parameters |
551 | // pnVersion - out parameter to hold the version number. |
552 | // |
553 | // Returns: |
554 | // S_OK on success. |
555 | //----------------------------------------------------------------------------- |
556 | HRESULT CordbFunction::GetActiveReJitRequestILCode(ICorDebugILCode **ppReJitedILCode) |
557 | { |
558 | HRESULT hr = S_OK; |
559 | VALIDATE_POINTER_TO_OBJECT(ppReJitedILCode, ICorDebugILCode **); |
560 | PUBLIC_API_BEGIN(this); |
561 | { |
562 | *ppReJitedILCode = NULL; |
563 | |
564 | VMPTR_ILCodeVersionNode vmILCodeVersionNode = VMPTR_ILCodeVersionNode::NullPtr(); |
565 | GetProcess()->GetDAC()->GetActiveRejitILCodeVersionNode(GetModule()->m_vmModule, m_MDToken, &vmILCodeVersionNode); |
566 | if (!vmILCodeVersionNode.IsNull()) |
567 | { |
568 | RSSmartPtr<CordbReJitILCode> pILCode; |
569 | IfFailThrow(LookupOrCreateReJitILCode(vmILCodeVersionNode, &pILCode)); |
570 | IfFailThrow(pILCode->QueryInterface(IID_ICorDebugILCode, (void**)ppReJitedILCode)); |
571 | } |
572 | } |
573 | PUBLIC_API_END(hr); |
574 | return hr; |
575 | } |
576 | |
577 | //----------------------------------------------------------------------------- |
578 | // CordbFunction::CreateNativeBreakpoint |
579 | // Public method for ICorDebugFunction4::CreateNativeBreakpoint. |
580 | // Sets a breakpoint at native offset 0 for all native code versions of a method. |
581 | // |
582 | // Parameters |
583 | // pnVersion - out parameter to hold the version number. |
584 | // |
585 | // Returns: |
586 | // S_OK on success. |
587 | //----------------------------------------------------------------------------- |
588 | HRESULT CordbFunction::CreateNativeBreakpoint(ICorDebugFunctionBreakpoint **ppBreakpoint) |
589 | { |
590 | PUBLIC_API_ENTRY(this); |
591 | FAIL_IF_NEUTERED(this); |
592 | VALIDATE_POINTER_TO_OBJECT(ppBreakpoint, ICorDebugFunctionBreakpoint **); |
593 | ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); |
594 | |
595 | HRESULT hr = S_OK; |
596 | |
597 | RSExtSmartPtr<CordbILCode> pCode; |
598 | |
599 | hr = GetILCode(&pCode); |
600 | |
601 | if (SUCCEEDED(hr)) |
602 | { |
603 | hr = pCode->CreateNativeBreakpoint(ppBreakpoint); |
604 | } |
605 | |
606 | return hr; |
607 | } |
608 | |
609 | // determine whether we have a native-only implementation |
610 | // Arguments: |
611 | // Input: none (we use information in various data members of this instance of CordbFunction: m_isNativeImpl, |
612 | // m_pIMImport, m_EnCCount) |
613 | // Output none, although we will set m_isNativeImpl to true iff the function has a native-only implementation |
614 | |
615 | void CordbFunction::InitNativeImpl() |
616 | { |
617 | INTERNAL_SYNC_API_ENTRY(GetProcess()); |
618 | |
619 | // Bail now if we've already discovered that this function is implemented natively as part of the Runtime. |
620 | if (m_fIsNativeImpl != kUnknownImpl) |
621 | { |
622 | return; |
623 | } |
624 | |
625 | // If we don't have a methodToken then we can't figure out what kind of function this is. This includes functions |
626 | // such as LCG and ILStubs. In the past we created codepaths that avoided ever calling in here in the common case |
627 | // and there would have been asserts and exceptions in the uncommon cases. Now I have just officially let the |
628 | // function handle staying as an 'unknown' impl. In such a state it provides no IL, no sigtoken, no native code, and |
629 | // no parent class. |
630 | if (m_MDToken == mdMethodDefNil) |
631 | { |
632 | return; |
633 | } |
634 | |
635 | // Figure out if this function is implemented as a native part of the Runtime. If it is, then this ICorDebugFunction |
636 | // is just a container for certain Right Side bits of info, i.e., module, class, token, etc. |
637 | DWORD attrs; |
638 | DWORD implAttrs; |
639 | ULONG ulRVA; |
640 | BOOL isDynamic; |
641 | |
642 | IfFailThrow(GetModule()->GetMetaDataImporter()->GetMethodProps(m_MDToken, NULL, NULL, 0, NULL, |
643 | &attrs, NULL, NULL, &ulRVA, &implAttrs)); |
644 | isDynamic = GetModule()->IsDynamic(); |
645 | |
646 | // A method has associated IL if its RVA is non-zero, unless it is a dynamic module |
647 | // @todo : if RVA is 0 and function has been EnC'd then it isn't native. Remove isEnC |
648 | // condition when the compilers stop generating 0 for an RVA. |
649 | BOOL isEnC = (GetModule()->m_EnCCount != 0); |
650 | if (IsMiNative(implAttrs) || ((isDynamic == FALSE) && (isEnC == FALSE) && (ulRVA == 0))) |
651 | { |
652 | |
653 | m_fIsNativeImpl = kNativeOnly; |
654 | } |
655 | else |
656 | { |
657 | m_fIsNativeImpl = kHasIL; |
658 | } |
659 | |
660 | } // CordbFunction::GetProcessAndCheckForNativeImpl |
661 | |
662 | // Returns the function's ILCode and SigToken |
663 | // Arguments: |
664 | // Input: none (required info comes from various data members of this instance of CordbFunction |
665 | // Output (required): |
666 | // none explicit, but this will: |
667 | // construct a new instance of CordbILCode and assign it to m_pILCode |
668 | |
669 | HRESULT CordbFunction::GetILCodeAndSigToken() |
670 | { |
671 | INTERNAL_SYNC_API_ENTRY(GetProcess()); |
672 | |
673 | CordbProcess * pProcess = m_pModule->GetProcess(); |
674 | HRESULT hr = S_OK; |
675 | |
676 | EX_TRY |
677 | { |
678 | |
679 | // ensure that we're not trying to get information about a native-only function |
680 | InitNativeImpl(); |
681 | if (m_fIsNativeImpl == kNativeOnly || m_fIsNativeImpl == kUnknownImpl) |
682 | { |
683 | ThrowHR(CORDBG_E_FUNCTION_NOT_IL); |
684 | } |
685 | |
686 | if (m_pILCode == NULL) |
687 | { |
688 | // we haven't gotten the information previously |
689 | |
690 | _ASSERTE(pProcess != NULL); |
691 | |
692 | // This target buffer and mdSignature might never have their values changed from the |
693 | // initial ones if the dump target is missing memory. TargetBuffer has a default |
694 | // constructor to zero its data and localVarSigToken is explicitly inited. |
695 | TargetBuffer codeInfo; |
696 | mdSignature localVarSigToken = mdSignatureNil; |
697 | SIZE_T currentEnCVersion; |
698 | |
699 | { |
700 | RSLockHolder lockHolder(GetProcess()->GetProcessLock()); |
701 | |
702 | // In the dump case we may not have the backing memory for this. In such a case |
703 | // we construct an empty ILCode object and leave the signatureToken as mdSignatureNil. |
704 | // It may also be the case that the memory we read from the dump be inconsistent (huge method size) |
705 | // and we also fallback on creating an empty ILCode object. |
706 | // See issue DD 273199 for cases where IL and NGEN metadata mismatch (different RVAs). |
707 | ALLOW_DATATARGET_MISSING_OR_INCONSISTENT_MEMORY( |
708 | pProcess->GetDAC()->GetILCodeAndSig(m_pModule->GetRuntimeDomainFile(), |
709 | m_MDToken, |
710 | &codeInfo, |
711 | &localVarSigToken); |
712 | ); |
713 | |
714 | currentEnCVersion = m_pModule->LookupFunctionLatestVersion(m_MDToken)->m_dwEnCVersionNumber; |
715 | } |
716 | |
717 | LOG((LF_CORDB,LL_INFO10000,"R:CF::GICAST: looking for IL code, version 0x%x\n" , currentEnCVersion)); |
718 | |
719 | if (m_pILCode == NULL) |
720 | { |
721 | LOG((LF_CORDB,LL_INFO10000,"R:CF::GICAST: not found, creating...\n" )); |
722 | if(codeInfo.pAddress == 0) |
723 | { |
724 | LOG((LF_CORDB,LL_INFO10000,"R:CF::GICAST: memory was missing - empty ILCode being created\n" )); |
725 | } |
726 | |
727 | // If everything succeeded, we set the IL code object (it's an outparam here). |
728 | _ASSERTE(m_pILCode == NULL); |
729 | m_pILCode.Assign(new(nothrow)CordbILCode(this, |
730 | codeInfo, |
731 | currentEnCVersion, |
732 | localVarSigToken)); |
733 | |
734 | if (m_pILCode == NULL) |
735 | { |
736 | ThrowHR(E_OUTOFMEMORY); |
737 | } |
738 | } |
739 | } |
740 | } |
741 | EX_CATCH_HRESULT(hr); |
742 | return hr; |
743 | } // CordbFunction::GetILCodeAndSigToken |
744 | |
745 | |
746 | // Get the metadata token for the class to which a function belongs. |
747 | // Arguments: |
748 | // Input: |
749 | // funcMetadataToken - the metadata token for the method |
750 | // Output (required): |
751 | // classMetadataToken - the metadata token for the class to which the method belongs |
752 | mdTypeDef CordbFunction::InitParentClassOfFunctionHelper(mdToken funcMetadataToken) |
753 | { |
754 | // Get the class this method is in. |
755 | mdToken tkParent = mdTypeDefNil; |
756 | IfFailThrow(GetModule()->GetInternalMD()->GetParentToken(funcMetadataToken, &tkParent)); |
757 | _ASSERTE(TypeFromToken(tkParent) == mdtTypeDef); |
758 | |
759 | return tkParent; |
760 | } // CordbFunction::InitParentClassOfFunctionHelper |
761 | |
762 | // Get the class to which a given function belongs |
763 | // Arguments: |
764 | // Input: none (required information comes from data members of this instance of CordbFunction) |
765 | // Output (required): none, but sets m_pClass |
766 | HRESULT CordbFunction::InitParentClassOfFunction() |
767 | { |
768 | INTERNAL_SYNC_API_ENTRY(GetProcess()); |
769 | |
770 | CordbProcess * pProcess = m_pModule->GetProcess(); |
771 | (void)pProcess; //prevent "unused variable" error from GCC |
772 | HRESULT hr = S_OK; |
773 | |
774 | EX_TRY |
775 | { |
776 | |
777 | // ensure that we're not trying to get information about a native-only function |
778 | InitNativeImpl(); |
779 | if (m_fIsNativeImpl == kNativeOnly || m_fIsNativeImpl == kUnknownImpl) |
780 | { |
781 | ThrowHR(CORDBG_E_FUNCTION_NOT_IL); |
782 | } |
783 | |
784 | mdTypeDef classMetadataToken; |
785 | VMPTR_DomainFile vmDomainFile = m_pModule->GetRuntimeDomainFile(); |
786 | |
787 | classMetadataToken = InitParentClassOfFunctionHelper(m_MDToken); |
788 | |
789 | if ((m_pClass == NULL) && (classMetadataToken != mdTypeDefNil)) |
790 | { |
791 | // we haven't gotten the information previously but we have it now |
792 | |
793 | _ASSERTE(pProcess != NULL); |
794 | |
795 | CordbAssembly *pAssembly = m_pModule->GetCordbAssembly(); |
796 | PREFIX_ASSUME(pAssembly != NULL); |
797 | |
798 | CordbModule* pClassModule = pAssembly->GetAppDomain()->LookupOrCreateModule(vmDomainFile); |
799 | PREFIX_ASSUME(pClassModule != NULL); |
800 | |
801 | CordbClass *pClass; |
802 | hr = pClassModule->LookupOrCreateClass(classMetadataToken, &pClass); |
803 | |
804 | IfFailThrow(hr); |
805 | |
806 | _ASSERTE(pClass != NULL); |
807 | m_pClass = pClass; |
808 | } |
809 | } |
810 | EX_CATCH_HRESULT(hr); |
811 | return hr; |
812 | |
813 | } // CordbFunction::InitParentClassOfFunction |
814 | |
815 | // Get information about the native code blob for a function and add it to m_nativeCodeTable |
816 | // Arguments: |
817 | // Input: none, but we use some data members of this instance of CordbFunction |
818 | // Output: standard HRESULT value |
819 | // Notes: Apart from the HRESULT, this function will build a new instance of CordbNativeCode and |
820 | // add it to the hash table of CordbNativeCodes for this function, unless we have done that |
821 | // previously |
822 | |
823 | HRESULT CordbFunction::InitNativeCodeInfo() |
824 | { |
825 | INTERNAL_SYNC_API_ENTRY(GetProcess()); |
826 | |
827 | CordbProcess * pProcess = m_pModule->GetProcess(); |
828 | HRESULT hr = S_OK; |
829 | |
830 | EX_TRY |
831 | { |
832 | |
833 | // ensure that we're not trying to get information about a native-only function |
834 | InitNativeImpl(); |
835 | if (m_fIsNativeImpl == kNativeOnly || m_fIsNativeImpl == kUnknownImpl) |
836 | { |
837 | ThrowHR(CORDBG_E_FUNCTION_NOT_IL); |
838 | } |
839 | |
840 | _ASSERTE(pProcess != NULL); |
841 | |
842 | // storage for information retrieved from the DAC. This is cleared in the constructor, so it |
843 | // won't contain garbage if we don't use the DAC to retrieve information we already got before. |
844 | NativeCodeFunctionData codeInfo; |
845 | |
846 | if (m_nativeCode == NULL) |
847 | { |
848 | // Get the native code information from the DAC |
849 | // PERF: this call is potentially more costly than it needs to be |
850 | // All we actually need is the start address and method desc which are cheap to get relative |
851 | // to some of the other members. So far this doesn't appear to be a perf hotspot, but if it |
852 | // shows up in some scenario it wouldn't be too hard to improve it |
853 | pProcess->GetDAC()->GetNativeCodeInfo(m_pModule->GetRuntimeDomainFile(), m_MDToken, &codeInfo); |
854 | } |
855 | |
856 | // populate the m_nativeCode pointer with the code info we found |
857 | if (codeInfo.IsValid()) |
858 | { |
859 | m_nativeCode.Assign(m_pModule->LookupOrCreateNativeCode(m_MDToken, codeInfo.vmNativeCodeMethodDescToken, |
860 | codeInfo.m_rgCodeRegions[kHot].pAddress)); |
861 | } |
862 | |
863 | } |
864 | EX_CATCH_HRESULT(hr); |
865 | return hr; |
866 | } // CordbFunction::InitNativeCodeInfo |
867 | |
868 | //----------------------------------------------------------------------------- |
869 | // CordbFunction::SetJMCStatus |
870 | // Public method (implements ICorDebugFunction2::SetJMCStatus). |
871 | // Set the JMC (eg, "User code" vs. "Non-user code") status of this function. |
872 | // |
873 | // Parameters: |
874 | // fIsUserCode - true to set this Function to JMC, else False. |
875 | // |
876 | // Returns: |
877 | // S_OK if successfully updated JMC status. |
878 | //----------------------------------------------------------------------------- |
879 | HRESULT CordbFunction::SetJMCStatus(BOOL fIsUserCode) |
880 | { |
881 | PUBLIC_REENTRANT_API_ENTRY(this); |
882 | HRESULT hr = S_OK; |
883 | |
884 | LOG((LF_CORDB,LL_INFO10000,"CordbFunction::SetJMCStatus to %d, (token=0x%08x, module=%p)\n" , |
885 | fIsUserCode, m_MDToken, m_pModule)); |
886 | |
887 | // Make sure the Left-Side is in a good state. |
888 | FAIL_IF_NEUTERED(this); |
889 | CordbProcess* pProcess = m_pModule->GetProcess(); |
890 | ATT_REQUIRE_STOPPED_MAY_FAIL(pProcess); |
891 | |
892 | |
893 | |
894 | // Send an event to the LS to keep it updated. |
895 | |
896 | // Validation - JMC Steppers don't have defined behavior if |
897 | // JMC method status gets toggled underneath them. However, we don't have |
898 | // a good way of verifying which methods are of interest to a JMC stepper. |
899 | // Having outstanding JMC steppers is dangerous here, but still can be |
900 | // done safely. |
901 | // Furthermore, debuggers may want to lazily set JMC status (such as when |
902 | // code is loaded), which may happen while we have outstanding steppers. |
903 | |
904 | |
905 | DebuggerIPCEvent event; |
906 | pProcess->InitIPCEvent(&event, DB_IPCE_SET_METHOD_JMC_STATUS, true, m_pModule->GetAppDomain()->GetADToken()); |
907 | event.SetJMCFunctionStatus.vmDomainFile = m_pModule->GetRuntimeDomainFile(); |
908 | event.SetJMCFunctionStatus.funcMetadataToken = m_MDToken; |
909 | event.SetJMCFunctionStatus.dwStatus = fIsUserCode; |
910 | |
911 | |
912 | // Note: two-way event here... |
913 | hr = pProcess->m_cordb->SendIPCEvent(pProcess, &event, sizeof(DebuggerIPCEvent)); |
914 | |
915 | // Stop now if we can't even send the event. |
916 | if (!SUCCEEDED(hr)) |
917 | return hr; |
918 | |
919 | _ASSERTE(event.type == DB_IPCE_SET_METHOD_JMC_STATUS_RESULT); |
920 | |
921 | return event.hr; |
922 | } |
923 | |
924 | //----------------------------------------------------------------------------- |
925 | // CordbFunction::GetJMCStatus |
926 | // Public function (implements ICorDebugFunction2::GetJMCStatus) |
927 | // Get the JMC status of this function. |
928 | // |
929 | // Parameters: |
930 | // pfIsUserCode - out parameter describing whether this method is user code. |
931 | // true iff this function is user code, else false. |
932 | // |
933 | // Return: |
934 | // returns S_OK if *pfIsUserCode is set. |
935 | //----------------------------------------------------------------------------- |
936 | HRESULT CordbFunction::GetJMCStatus(BOOL * pfIsUserCode) |
937 | { |
938 | PUBLIC_REENTRANT_API_ENTRY(this); |
939 | FAIL_IF_NEUTERED(this); |
940 | ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); |
941 | VALIDATE_POINTER_TO_OBJECT(pfIsUserCode, BOOL*); |
942 | |
943 | |
944 | _ASSERTE(pfIsUserCode != NULL); |
945 | if (pfIsUserCode == NULL) |
946 | return E_INVALIDARG; |
947 | |
948 | // <TODO> @perf - If we know that we haven't updated the JMC status on anything |
949 | // in this module (we could keep a dirty flag), then we can just cache |
950 | // the jmc status and not send an event to query each time. </TODO> |
951 | |
952 | // Make sure the process is in a sane state. |
953 | CordbProcess* pProcess = m_pModule->GetProcess(); |
954 | _ASSERTE(pProcess != NULL); |
955 | |
956 | // Ask the left-side if a method is user code or not. |
957 | DebuggerIPCEvent event; |
958 | pProcess->InitIPCEvent(&event, DB_IPCE_GET_METHOD_JMC_STATUS, true, m_pModule->GetAppDomain()->GetADToken()); |
959 | event.SetJMCFunctionStatus.vmDomainFile = m_pModule->GetRuntimeDomainFile(); |
960 | event.SetJMCFunctionStatus.funcMetadataToken = m_MDToken; |
961 | |
962 | |
963 | // Note: two-way event here... |
964 | HRESULT hr = pProcess->m_cordb->SendIPCEvent(pProcess, &event, sizeof(DebuggerIPCEvent)); |
965 | |
966 | // Stop now if we can't even send the event. |
967 | if (!SUCCEEDED(hr)) |
968 | return hr; |
969 | |
970 | _ASSERTE(event.type == DB_IPCE_GET_METHOD_JMC_STATUS_RESULT); |
971 | |
972 | // update our internal copy of the status. |
973 | BOOL fIsUserCode = event.SetJMCFunctionStatus.dwStatus; |
974 | |
975 | *pfIsUserCode = fIsUserCode; |
976 | |
977 | return event.hr; |
978 | } |
979 | |
980 | |
981 | /* |
982 | * CordbFunction::GetSig |
983 | * |
984 | * Get the method's full metadata signature. This may be cached, but for dynamic modules we'll always read it from |
985 | * the metadata. This function also returns the argument count and whether or not the method is static. |
986 | * |
987 | * Parameters: |
988 | * pMethodSigParser - OUT: the signature parser class to use for all signature parsing. |
989 | * pFunctionArgCount - OUT: the number of arguments the method takes. |
990 | * pFunctionIsStatic - OUT: TRUE if the method is static, FALSE if it is not.. |
991 | * |
992 | * Returns: |
993 | * HRESULT for success or failure. |
994 | * |
995 | */ |
996 | HRESULT CordbFunction::GetSig(SigParser *pMethodSigParser, |
997 | ULONG *pFunctionArgCount, |
998 | BOOL *pFunctionIsStatic) |
999 | { |
1000 | INTERNAL_API_ENTRY(this); |
1001 | FAIL_IF_NEUTERED(this); |
1002 | |
1003 | HRESULT hr = S_OK; |
1004 | |
1005 | // If the module is dynamic, there had better not be a cached locals signature. |
1006 | _ASSERTE(!GetModule()->IsDynamic() || !m_fCachedMethodValuesValid); |
1007 | |
1008 | // If the method signature cache is null, then go read the signature from the |
1009 | // matadata. For dynamic methods we never cache the parser because the method |
1010 | // may change and the cached value will not match. |
1011 | if (!m_fCachedMethodValuesValid) |
1012 | { |
1013 | PCCOR_SIGNATURE functionSignature; |
1014 | ULONG size; |
1015 | DWORD methodAttr = 0; |
1016 | ULONG argCount; |
1017 | |
1018 | EX_TRY // @dbgtotod - push this up |
1019 | { |
1020 | hr = GetModule()->GetMetaDataImporter()->GetMethodProps(m_MDToken, NULL, NULL, 0, NULL, |
1021 | &methodAttr, &functionSignature, &size, NULL, NULL); |
1022 | } |
1023 | EX_CATCH_HRESULT(hr); |
1024 | IfFailRet(hr); |
1025 | |
1026 | SigParser sigParser = SigParser(functionSignature, size); |
1027 | |
1028 | IfFailRet(sigParser.SkipMethodHeaderSignature(&argCount)); |
1029 | |
1030 | // If this function is not static, then we've got one extra arg. |
1031 | BOOL isStatic = (methodAttr & mdStatic) != 0; |
1032 | |
1033 | if (!isStatic) |
1034 | { |
1035 | argCount++; |
1036 | } |
1037 | |
1038 | // Cache the value for non-dynamic modules, so this is faster later. |
1039 | if (!GetModule()->IsDynamic()) |
1040 | { |
1041 | m_methodSigParserCached = sigParser; |
1042 | m_argCountCached = argCount; |
1043 | m_fIsStaticCached = isStatic; |
1044 | m_fCachedMethodValuesValid = TRUE; |
1045 | } |
1046 | else |
1047 | { |
1048 | // This is the Dynamic method case, so we can't cache. Just leave fields blank |
1049 | // and set out-parameters based off locals. |
1050 | if (pMethodSigParser != NULL) |
1051 | { |
1052 | *pMethodSigParser = sigParser; |
1053 | } |
1054 | |
1055 | if (pFunctionArgCount != NULL) |
1056 | { |
1057 | *pFunctionArgCount = argCount; |
1058 | } |
1059 | |
1060 | if (pFunctionIsStatic != NULL) |
1061 | { |
1062 | *pFunctionIsStatic = isStatic; |
1063 | } |
1064 | } |
1065 | } |
1066 | |
1067 | if (m_fCachedMethodValuesValid) |
1068 | { |
1069 | // |
1070 | // Retrieve values from cache |
1071 | // |
1072 | |
1073 | if (pMethodSigParser != NULL) |
1074 | { |
1075 | // |
1076 | // Give them a new instance of the cached value |
1077 | // |
1078 | *pMethodSigParser = m_methodSigParserCached; |
1079 | } |
1080 | |
1081 | if (pFunctionArgCount != NULL) |
1082 | { |
1083 | *pFunctionArgCount = m_argCountCached; |
1084 | } |
1085 | |
1086 | if (pFunctionIsStatic != NULL) |
1087 | { |
1088 | *pFunctionIsStatic = m_fIsStaticCached; |
1089 | } |
1090 | |
1091 | } |
1092 | |
1093 | // |
1094 | // We should never have a cached value for in a dynamic module. |
1095 | // |
1096 | CONSISTENCY_CHECK_MSGF(((GetModule()->IsDynamic() && !m_fCachedMethodValuesValid) || |
1097 | (!GetModule()->IsDynamic() && m_fCachedMethodValuesValid)), |
1098 | ("No dynamic modules should be cached! Module=%p This=%p" , GetModule(), this)); |
1099 | |
1100 | return hr; |
1101 | } |
1102 | |
1103 | |
1104 | //----------------------------------------------------------------------------- |
1105 | // CordbFunction::GetArgumentType |
1106 | // Internal method. Given an 0-based IL argument number, return its type. |
1107 | // This can't access hidden parameters. |
1108 | // |
1109 | // Parameters: |
1110 | // dwIndex - 0-based index for IL argument number. For instance types, |
1111 | // 'this' argument is #0. For static types, first argument is #0. |
1112 | // pInst - instantiation information if this is a generic function. Eg, |
1113 | // if function is List<T>, inst describes T. |
1114 | // ppResultType - out parameter, yields to CordbType of the argument. |
1115 | // |
1116 | // Return: |
1117 | // S_OK on success. |
1118 | // |
1119 | HRESULT CordbFunction::GetArgumentType(DWORD dwIndex, |
1120 | const Instantiation * pInst, |
1121 | CordbType ** ppResultType) |
1122 | { |
1123 | FAIL_IF_NEUTERED(this); |
1124 | INTERNAL_SYNC_API_ENTRY(GetProcess()); |
1125 | |
1126 | HRESULT hr = S_OK; |
1127 | |
1128 | // Get the method's signature, which contains the types for all the arguments. |
1129 | SigParser sigParser; |
1130 | ULONG cMethodArgs; |
1131 | BOOL fMethodIsStatic; |
1132 | |
1133 | IfFailRet(GetSig(&sigParser, &cMethodArgs, &fMethodIsStatic)); |
1134 | |
1135 | // Check the index |
1136 | if (dwIndex >= cMethodArgs) |
1137 | { |
1138 | return E_INVALIDARG; |
1139 | } |
1140 | |
1141 | if (!fMethodIsStatic) |
1142 | { |
1143 | if (dwIndex == 0) |
1144 | { |
1145 | // Return the signature for the 'this' pointer for the |
1146 | // class this method is in. |
1147 | return m_pClass->GetThisType(pInst, ppResultType); |
1148 | } |
1149 | else |
1150 | { |
1151 | dwIndex--; |
1152 | } |
1153 | } |
1154 | |
1155 | // Run the signature and find the required argument. |
1156 | for (unsigned int i = 0; i < dwIndex; i++) |
1157 | { |
1158 | IfFailRet(sigParser.SkipExactlyOne()); |
1159 | } |
1160 | |
1161 | hr = CordbType::SigToType(m_pModule, &sigParser, pInst, ppResultType); |
1162 | |
1163 | return hr; |
1164 | } |
1165 | |
1166 | //----------------------------------------------------------------------------- |
1167 | // CordbFunction::NotifyCodeCreated |
1168 | // Internal method. Allows CordbFunctions to get access to a canonical native code entry |
1169 | // that they will return when asked for native code. The 1:1 mapping between |
1170 | // function and code was invalidated by generics but debuggers continue to use |
1171 | // the old API. When they do we need to have some code to hand them back even |
1172 | // though it is an arbitrary instantiation. Note that that the cannonical code |
1173 | // here is merely the first one that a user inspects... it is not guaranteed to |
1174 | // be the same in each debugging session but once set it will never change. It is |
1175 | // also definately NOT guaranteed to be the instantation over the runtime type |
1176 | // __Canon. |
1177 | // |
1178 | // Parameters: |
1179 | // nativeCode - the code which corresponds to this function |
1180 | // |
1181 | VOID CordbFunction::NotifyCodeCreated(CordbNativeCode* nativeCode) |
1182 | { |
1183 | INTERNAL_SYNC_API_ENTRY(GetProcess()); |
1184 | CONTRACTL |
1185 | { |
1186 | NOTHROW; |
1187 | } |
1188 | CONTRACTL_END; |
1189 | |
1190 | // Grab this native code as the canonical one if we don't already |
1191 | // have a canonical entry |
1192 | if(m_nativeCode == NULL) |
1193 | m_nativeCode.Assign(nativeCode); |
1194 | } |
1195 | |
1196 | |
1197 | //----------------------------------------------------------------------------- |
1198 | // LookupOrCreateReJitILCode finds an existing version of CordbReJitILCode in the given function. |
1199 | // If the CordbReJitILCode doesn't exist, it creates it. |
1200 | // |
1201 | // |
1202 | HRESULT CordbFunction::LookupOrCreateReJitILCode(VMPTR_ILCodeVersionNode vmILCodeVersionNode, CordbReJitILCode** ppILCode) |
1203 | { |
1204 | INTERNAL_API_ENTRY(this); |
1205 | |
1206 | HRESULT hr = S_OK; |
1207 | _ASSERTE(GetProcess()->ThreadHoldsProcessLock()); |
1208 | |
1209 | CordbReJitILCode * pILCode = m_reJitILCodes.GetBase(VmPtrToCookie(vmILCodeVersionNode)); |
1210 | |
1211 | // special case non-existance as need to add to the hash table too |
1212 | if (pILCode == NULL) |
1213 | { |
1214 | // we don't yet support ENC and ReJIT together, so the version should be 1 |
1215 | _ASSERTE(m_dwEnCVersionNumber == 1); |
1216 | RSInitHolder<CordbReJitILCode> pILCodeHolder(new CordbReJitILCode(this, 1, vmILCodeVersionNode)); |
1217 | IfFailRet(m_reJitILCodes.AddBase(pILCodeHolder)); |
1218 | pILCode = pILCodeHolder; |
1219 | pILCodeHolder.ClearAndMarkDontNeuter(); |
1220 | } |
1221 | |
1222 | pILCode->InternalAddRef(); |
1223 | *ppILCode = pILCode; |
1224 | return S_OK; |
1225 | } |
1226 | |