Visual Studio 2015標準ライブラリとテレメトリー

前文



CおよびC ++プログラムは、ほとんどの人生をmain()



関数内で費やし、 main()



から直接または間接的に呼び出される関数を費やす傾向があります。 ただし、実際には、プログラムの実行はmain()



で始まるのではなく、コンパイラに付属する標準ライブラリのコードで始まります。 そのようなコードは、理論的には、 main()



によって呼び出される可能性のある標準ライブラリの他の関数の環境、およびmain()



パラメーターを準備するargc/argv/envp



があります(Windows; Unixシステムは、準備された形式でargc/argv/envp



を渡す傾向がありますmain()



プロセスを開始するときですが、それはそれらについてではありません)。 対称的に、 main()



関数の最後のreturn



は、プログラムの最後の命令ではありません。標準ライブラリからもう少しコードが続きます。

Visual Studioでは、プログラムへの「実際の」エントリポイントはmainCRTStartup



と呼ばれmainCRTStartup



。 標準ライブラリのソースコードはVSに付属しています。VS2015では、mainCRTStartupの定義は%PROGRAMFILES(X86)%\VC\crt\src\vcruntime\exe_main.cpp



にありますが、ちなみに、 exe_common.inl



は近くのすべての作業を行います。 そこを見てみましょう。

 ... // If this module has any thread-local destructors, register the // callback function with the Unified CRT to run on exit. _tls_callback_type const * const tls_dtor_callback = __scrt_get_dyn_tls_dtor_callback(); if (*tls_dtor_callback != nullptr && __scrt_is_nonwritable_in_current_image(tls_dtor_callback)) { _register_thread_local_exe_atexit_callback(*tls_dtor_callback); } __telemetry_main_invoke_trigger(nullptr); // // Initialization is complete; invoke main... // int const main_result = invoke_main(); // // main has returned; exit somehow... // __telemetry_main_return_trigger(nullptr); if (!__scrt_is_managed_app()) exit(main_result); if (!has_cctor) _cexit(); // Finally, we terminate the CRT: __scrt_uninitialize_crt(true, false); return main_result; ...
      
      









もっと深く



経験豊富な妄想家は、間違いなく__telemetry_main_invoke_trigger



__telemetry_main_return_trigger



課題にすでに気付いています。 それらのソースを見つけてみましょう...と置物。 これらの関数内に移動しようとすると、VSデバッガーは「telemetry.cpp not found」(MSが配信に含めるのを忘れたソースファイルはtelemetry.cppと呼ばれることを意味します。論理的に)を報告し、パスを手動で指定するか、逆アセンブルされたコード。

__vcrt_initialize_telemetry_provider



から他の関数​​を注意深く検索すると、初期化および完了時にそれぞれ呼び出される関数__vcrt_initialize_telemetry_provider



および__vcrt_uninitialize_telemetry_provider



さらにいくつか見つかります。



もちろん、ソースを提供できなかったからといって、内部を見ることはできません。 逆アセンブルされたコードを調べると、タイプconst __vcrt_trace_logging_provider::_TlgProvider_t* const



の_Microsoft_CRTProvider変数につながり、タイプ_TlgProvider_t



もはや秘密で_TlgProvider_t



なく、SDKに簡単に配置されます: %PROGRAMFILES(X86)%\Windows Kits\10\Include\10.0.10586.0\shared\TraceLoggingProvider.h



... そして、ここにドキュメントがあります 。 (ドキュメントには「Windows 10」と書かれていますが、これはコードがWindows 7で動作することを妨げるものではありません。)では、これらすべてのログをどこに書き込むのでしょうか。

このセクションで説明するように、TraceLoggingイベントはETWに送信されます。
つまり、これはWindowsサブシステムのイベントトレースの別の化身です。 うん。

ETWという略語を最初に聞いた人への簡単なリファレンス:これは、Windows 2000で登場し、Vistaで大幅に増加した、あらゆる種類のログとカウンタの統合処理のためのインフラストラクチャです。 希望する場合は、コマンドプロンプトでlogman query providers



を入力して、スケールを評価できます。




ログを見る



例えば、いくつかの簡単なプログラムを見てみましょう:

 #include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }
      
      





cl /Os hello.c



によるコンパイル結果: yadi.sk/d/pa0S5qVoqw9Q4

そのため、コンパイルされたexe-shnikには、 main()



呼び出す前後のいくつかのログの記録があるはずです。 ETWサブシステムは、ロギング用のコマンドがなかったものをすべて破棄します。 ログをオンにしましょう:管理者名、

 logman create trace test_crt_telemetry -p {5EEC90AB-C022-44B2-A5DD-FD716A222A15} -o C:\temp\test_telemetry logman start test_crt_telemetry
      
      





logman



必要なlogman



tracerpt



は、Windowsの標準ユーティリティです)。 {5EEC90AB-C022-44B2-A5DD-FD716A222A15}はどこで入手しましたか? 既に説明した変数_Microsoft_CRTProvider



表示すると、VSデバッガーが表示され_Microsoft_CRTProvider





hello.exeを起動すると、古典的な挨拶が表示されます。 ログをファイルにリセットし、

 logman stop test_crt_telemetry
      
      





そしてそこに書かれているものを見てください:

 tracerpt -summary summary.txt -o dumpfile.xml C:\temp\test_telemetry_000001.etl
      
      





 <Events> <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event"> <System> <Provider Name="Microsoft.CRTProvider" Guid="{5eec90ab-c022-44b2-a5dd-fd716a222a15}" /> <EventID>17</EventID> <Version>0</Version> <Level>5</Level> <Task>0</Task> <Opcode>0</Opcode> <Keywords>0x200000000000</Keywords> <TimeCreated SystemTime="2016-04-11T00:57:29.437589800Z" /> <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" /> <Execution ProcessID="7656" ThreadID="5796" ProcessorID="0" KernelTime="0" UserTime="0" /> <Channel /> <Computer /> </System> <EventData> <Data Name="&quot;Main Invoked.&quot;">Main Invoked.</Data> <Data Name="FileName">C:\temp\hello.exe</Data> </EventData> <RenderingInfo Culture="ru-RU"> <Task>InvokeMainViaCRT</Task> </RenderingInfo> </Event> <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event"> <System> <Provider Name="Microsoft.CRTProvider" Guid="{5eec90ab-c022-44b2-a5dd-fd716a222a15}" /> <EventID>77</EventID> <Version>0</Version> <Level>5</Level> <Task>0</Task> <Opcode>0</Opcode> <Keywords>0x200000000000</Keywords> <TimeCreated SystemTime="2016-04-11T00:57:29.437734300Z" /> <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" /> <Execution ProcessID="7656" ThreadID="5796" ProcessorID="0" KernelTime="0" UserTime="0" /> <Channel /> <Computer /> </System> <EventData> <Data Name="&quot;Main Returned.&quot;">Main Returned.</Data> <Data Name="FileName">C:\temp\hello.exe</Data> </EventData> <RenderingInfo Culture="ru-RU"> <Task>ExitMainViaCRT</Task> </RenderingInfo> </Event>
      
      





はい、ログがあります。 ただし、多くのデータはありません。main main()



および標準ETWヘッダーの呼び出し/戻りに関するメッセージに加えて、exe-shnikの名前のみが書き込まれます。



ちなみに、ログエントリをオンのままにして作業した場合はどうなりますか? たとえば、キャッチできます

 <EventData> <Data Name="&quot;Main Invoked.&quot;">Main Invoked.</Data> <Data Name="FileName">C:\Program Files\Python 3.5\python35.dll</Data> </EventData> <EventData> <Data Name="&quot;Main Invoked.&quot;">Main Invoked.</Data> <Data Name="FileName">C:\Program Files\Python 3.5\python.exe</Data> </EventData> <EventData> <Data Name="&quot;Main Returned.&quot;">Main Returned.</Data> <Data Name="FileName">C:\Program Files\Python 3.5\python.exe</Data> </EventData> <EventData> <Data Name="&quot;Main Returned.&quot;">Main Returned.</Data> <Data Name="FileName">C:\Program Files\Python 3.5\python35.dll</Data> </EventData>
      
      





Pythonは進歩を続けています! 申し訳ありませんが、Python 3は進捗状況を把握しています。



パニックにならないで



最後に何がありますか?




All Articles