调试Rotor: 启动过程
引言:
我已经深入一些书籍好长一段时间了, 包括(Essential.Net, Shared Source CLI, Shared Source Internals, Distributed Virtual machine, ECMA335), 然而纸上得来终觉浅,绝知此事要躬行, 我的默认试验环境是:
- Windows 2008 / Visual Studio 2008 SP1 / .Net Framework 3.5 SP1 / SSCLI2.0
在本文中,我将在Visual Studio 2008中使用一个简单的例子来解释Rotor的启动过程
例子代码文件: %Rotor_DIR%/Samples/Hello/hello.cs
如何Debug?
如果您不知道,可以看这里, 简单的步骤如下面所示
- cd E:/Research/MyRotor // 请根据您的Rotor目录修改
- env // 设置环境变量
- cd samples/hello
- csc /debug hello.cs // 编译代码
- devenv /debugexe clix hello.exe // 调试clix
按F11就可以到程序执行的第一行代码了
图 1: 调试的第一行代码
这个文件在 %Rotor_DIR%\palrt\inc\palstartup.h
启动过程
Figure 2: 大概的启动过程
Figure 3: 启动中主要执行的过程
我已经进行一次启动过程的调试,启动过程如下图所示.
Figure 4: the loading process in sscli2.0
代码文件:
- \pal\win32\win32pal.c
- \clr\src\tools\clix\clix.cpp
- \palrt\sscoree\sscoree_int.cpp
- \clr\src\vm\ceemain.cpp
- \clr\src\vm\appdomain.cpp
ExecuteMainMethod中的一些执行过程放在了下面的代码中,有兴趣的读者不妨一读
Code
Thread *pThread = GetThread();
FrameWithCookie<ContextTransitionFrame> frame;
pThread->EnterContextRestricted(SystemDomain::System()->DefaultDomain()->GetDefaultContext(), &frame);
AppDomain *pDomain = GetAppDomain();
FrameWithCookie<DebuggerClassInitMarkFrame> __dcimf;
PEImageHolder pTempImage(PEImage::OpenImage(path));
if (!pTempImage->CheckILFormat())
{
ThrowHR(COR_E_BADIMAGEFORMAT);
}
PEFileHolder pTempFile(PEFile::Open(pTempImage.Extract()));
// Check for CustomAttributes - Set up the DefaultDomain and the main thread
// Note that this has to be done before ExplicitBind() as it
// affects the bind
mdToken tkEntryPoint = pTempFile->GetEntryPointToken();
ReleaseHolder<IMDInternalImport> scope(pTempFile->GetMDImportWithRef());
// This can potentially run managed code.
InitializeDefaultDomain(FALSE);
if((!IsNilToken(tkEntryPoint)) && (TypeFromToken(tkEntryPoint) == mdtMethodDef))
SystemDomain::SetDefaultDomainAttributes(scope, tkEntryPoint);
NewHolder<PEFileSecurityDescriptor> pSecDesc(new PEFileSecurityDescriptor(pDomain, pTempFile));
Security::Resolve(pSecDesc);
if (Security::AllowBindingRedirects(pSecDesc))
pDomain->TurnOnBindingRedirects();
SafeComHolder<IAssembly> pFusionAssembly;
SafeComHolder<IFusionBindLog> pFusionLog;
IfFailThrow(ExplicitBind(path, pDomain->GetFusionContext(),
EXPLICITBIND_FLAGS_EXE,
NULL, &pFusionAssembly, NULL, &pFusionLog));
PEAssemblyHolder pFile(PEAssembly::Open(pFusionAssembly, NULL, pFusionLog));
pDomain->m_pRootAssembly = GetAppDomain()->LoadAssembly(NULL, pFile, FILE_ACTIVE);
if (CorCommandLine::m_pwszAppFullName == NULL) {
StackSString friendlyName;
StackSString assemblyPath = pFile->GetPath();
SString::Iterator i = assemblyPath.End();
if (PEAssembly::FindLastPathSeparator(assemblyPath, i)) {
i++;
friendlyName.Set(assemblyPath, i, assemblyPath.End());
}
else
friendlyName.Set(assemblyPath);
pDomain->SetFriendlyName(friendlyName, TRUE);
}
__dcimf.Pop();
结语
本来想再细致点,慢慢来吧,累,而且俺还懒。还有很多东西值得深入,比如meta token的验证,cil代码的验证, Main 方法的即时编译(JIT),先留着,:)