#前回のまとめ
LibreOfficeをgud-gdbで追えるようになった。バンザイ。
#デバッガで追えるところまで追ってみる
##とりあえずbt
前回やったようにLibreOfficeを起動してみたけど、恐ろしいくらい起動が遅い。2分くらいかかった。たぶんデバッグシンボルを付けたから遅いのだろう。毎回この時間待つのはかなり苦痛なのだが、まあ仕方ない…。
Emacs上でC-c C-cを押すと、実行を中断することができる。ここでbtを押すとどの関数が呼ばれているかわかる。
目的の関数とかを探すためにgrepで検索したいのだが、全ソースを検索していたら時間がいくらあっても足りない。calcに関係ありそうなところだけに絞って検索したい!
というわけで、btで見つけたファイルを手探ってみよう。
(gdb) bt
#0 0x00007ffff755c12d in poll () at ../sysdeps/unix/syscall-template.S:81
#1 0x00007fffe30d4fe4 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#2 0x00007fffe30d50ec in g_main_context_iteration ()
from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#3 0x00007fffe3b6a3e3 in GtkData::Yield (this=0x6284e0, bWait=true,
bHandleAllCurrentEvents=false)
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/vcl/unx/gtk/app/gtkdata.cxx:575
#4 0x00007fffe3b6e34c in GtkInstance::Yield (this=0x628430, bWait=true,
bHandleAllCurrentEvents=false)
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/vcl/unx/gtk/app/gtkinst.cxx:406
#5 0x00007ffff12a5208 in ImplYield (i_bWait=true, i_bAllEvents=false)
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/vcl/source/app/svapp.cxx:360
#6 0x00007ffff12a1c69 in Application::Yield ()
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/vcl/source/app/svapp.cxx:392
#7 0x00007ffff12a1c17 in Application::Execute ()
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/vcl/source/app/svapp.cxx:341
#8 0x00007ffff784f29f in desktop::Desktop::Main (this=0x7fffffffe170)
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/desktop/source/app/app.cxx:1638
#9 0x00007ffff12a92fa in ImplSVMain ()
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/vcl/source/app/svmain.cxx:163
#10 0x00007ffff12a93f0 in SVMain ()
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/vcl/source/app/svmain.cxx:196
#11 0x00007ffff7892a97 in soffice_main ()
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/desktop/source/app/sofficemain.cxx:101
#12 0x0000000000400964 in sal_main ()
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/desktop/source/app/main.c:48
#13 0x000000000040094a in main (argc=2, argv=0x7fffffffe418)
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/desktop/source/app/main.c:47
ためしに、ImplYield ()
を見てみる。
inline void ImplYield( bool i_bWait, bool i_bAllEvents )
{
ImplSVData* pSVData = ImplGetSVData();
// run timers that have timed out
if ( !pSVData->mbNoCallTimer )
while ( pSVData->mbNotAllTimerCalled )
Timer::ImplTimerCallbackProc();
pSVData->maAppData.mnDispatchLevel++;
// do not wait for events if application was already quit; in that
// case only dispatch events already available
// do not wait for events either if the app decided that it is too busy for timers
// (feature added for the slideshow)
pSVData->mpDefInst->Yield( i_bWait && !pSVData->maAppData.mbAppQuit && !pSVData->maAppData.mbNoYield, i_bAllEvents );
pSVData->maAppData.mnDispatchLevel--;
DBG_TESTSOLARMUTEX(); // must be locked on return from Yield
// flush lazy deleted objects
if( pSVData->maAppData.mnDispatchLevel == 0 )
vcl::LazyDelete::flush();
// the system timer events will not necessarily come in non waiting mode
// e.g. on OS X; need to trigger timer checks manually
if( pSVData->maAppData.mbNoYield && !pSVData->mbNoCallTimer )
{
do
{
Timer::ImplTimerCallbackProc();
}
while( pSVData->mbNotAllTimerCalled );
}
// call post yield listeners
if( pSVData->maAppData.mpPostYieldListeners )
pSVData->maAppData.mpPostYieldListeners->callListeners( NULL );
}
##find-tag用のタグファイルを作成
ImplSVData
クラスを探してみる…とその前に、先にfind-tag
を使えるようにする。
$ find . -regex ".*\.+\(c\|cxx\|h\|hxx\)" -print | etags -
##タグ検索でどんどん奥へ
struct ImplSVData
{
SalData* mpSalData;
SalInstance* mpDefInst; // Default SalInstance
Application* mpApp; // pApp
WorkWindow* mpDefaultWin; // Default-Window
bool mbDeInit; // Is VCL deinitializing
sal_uLong mnThreadCount; // is VCL MultiThread enabled
ImplConfigData* mpFirstConfigData; // Zeiger auf ersten Config-Block
ImplTimerData* mpFirstTimerData; // list of all running timers
SalTimer* mpSalTimer; // interface to sal event loop/timers
SalI18NImeStatus* mpImeStatus; // interface to ime status window
SalSystem* mpSalSystem; // SalSystem interface
ResMgr* mpResMgr; // SV-Resource-Manager
sal_uLong mnTimerPeriod; // current timer period
sal_uLong mnTimerUpdate; // TimerCallbackProcs on stack
bool mbNotAllTimerCalled;// true: Es muessen noch Timer abgearbeitet werden
bool mbNoCallTimer; // true: No Timeout calls
ImplSVAppData maAppData; // indepen data for class Application
ImplSVGDIData maGDIData; // indepen data for Output classes
ImplSVWinData maWinData; // indepen data for Windows classes
ImplSVCtrlData maCtrlData; // indepen data for Control classes
ImplSVHelpData maHelpData; // indepen data for Help classes
ImplSVNWFData maNWFData;
UnoWrapperBase* mpUnoWrapper;
vcl::Window* mpIntroWindow; // the splash screen
DockingManager* mpDockingManager;
BlendFrameCache* mpBlendFrameCache;
bool mbIsTestTool;
oslThreadIdentifier mnMainThreadId;
rtl::Reference< vcl::DisplayConnection > mxDisplayConnection;
::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > mxAccessBridge;
::vcl::SettingsConfigItem* mpSettingsConfigItem;
std::list< vcl::DeleteOnDeinitBase* >* mpDeinitDeleteList;
boost::unordered_map< int, OUString >* mpPaperNames;
Link maDeInitHook;
};
Yield()
関数を持っているmpDefInstメンバは、SalInstanceというクラス?のインスタンスらしい。そこで、こんどはこれを検索してみる。
// This is our main entry point:
SalInstance *CreateSalInstance()
{
HeadlessSalInstance* pInstance = new HeadlessSalInstance( new SalYieldMutex() );
new HeadlessSalData( pInstance );
pInstance->AcquireYieldMutex(1);
return pInstance;
}
「This is our main entry point :」という言葉に感慨を覚えつつ、さらに奥へ。
HeadlessSalInstanceクラスがSalInstanceクラスの実体(?)のようなので、今度はこっちをfind-tag。
class HeadlessSalInstance : public SvpSalInstance
{
public:
HeadlessSalInstance( SalYieldMutex *pMutex );
virtual ~HeadlessSalInstance();
virtual SalSystem* CreateSalSystem();
};
え、これだけ?
コンストラクタの実装は以下
HeadlessSalInstance::HeadlessSalInstance( SalYieldMutex *pMutex ) :
SvpSalInstance( pMutex)
{
}
このコロンについて調べたところ(C++全然わからない)、どうやらメンバ変数を初期化する構文らしい。
HogeClass () :
var (value)
{
// 内容
}
で、var
にvalue
を代入するコンストラクタになる。
##btのデータを元に、上の方へ進んでみる
bool InitVCL()
{
if( pExceptionHandler != NULL )
return false;
EmbeddedFontsHelper::clearTemporaryFontFiles();
if( ! ImplGetSVData() )
ImplInitSVData();
if( !ImplGetSVData()->mpApp )
{
pOwnSvApp = new DummyApplication();
}
InitSalMain();
ImplSVData* pSVData = ImplGetSVData();
// remember Main-Thread-Id
pSVData->mnMainThreadId = ::osl::Thread::getCurrentIdentifier();
// Initialize Sal
pSVData->mpDefInst = CreateSalInstance();
if ( !pSVData->mpDefInst )
return false;
// Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
com::sun::star::uno::setCurrentContext(
new DesktopEnvironmentContext( com::sun::star::uno::getCurrentContext() ) );
// Initialize application instance (should be done after initialization of VCL SAL part)
if( pSVData->mpApp )
// call init to initialize application class
// soffice/sfx implementation creates the global service manager
pSVData->mpApp->Init();
pSVData->mpDefInst->AfterAppInit();
// Fetch AppFileName and make it absolute before the workdir changes...
OUString aExeFileName;
osl_getExecutableFile( &aExeFileName.pData );
// convert path to native file format
OUString aNativeFileName;
osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
pSVData->maAppData.mpAppFileName = new OUString( aNativeFileName );
// Initialize global data
pSVData->maGDIData.mpScreenFontList = new PhysicalFontCollection;
pSVData->maGDIData.mpScreenFontCache = new ImplFontCache;
pSVData->maGDIData.mpGrfConverter = new GraphicConverter;
// Set exception handler
pExceptionHandler = osl_addSignalHandler(VCLExceptionSignal_impl, NULL);
DBGGUI_INIT_SOLARMUTEXCHECK();
#if OSL_DEBUG_LEVEL > 0
DebugEventInjector::getCreate();
#endif
return true;
}
これがCreateSalInstance()
を呼び出してた関数。いかにも初期化しますって顔してて、めちゃくちゃ怪しいけど、どうにも何やってるかよくわかんない…。
pSVData->mpApp->Init();
を実行すると、新しいスレッドが2つ立ち上がった。その1つ下の行を実行すると、さっき立ち上がったスレッドのうち先に立ち上がったほうが閉じて、2つ新規スレッドが立ち上がる。
int ImplSVMain()
{
// The 'real' SVMain()
ImplSVData* pSVData = ImplGetSVData();
DBG_ASSERT( pSVData->mpApp, "no instance of class Application" );
int nReturn = EXIT_FAILURE;
bool bInit = InitVCL();
if( bInit )
{
// call application main
pSVData->maAppData.mbInAppMain = true;
nReturn = pSVData->mpApp->Main();
pSVData->maAppData.mbInAppMain = false;
}
if( pSVData->mxDisplayConnection.is() )
{
pSVData->mxDisplayConnection->terminate();
pSVData->mxDisplayConnection.clear();
}
// This is a hack to work around the problem of the asynchronous nature
// of bridging accessibility through Java: on shutdown there might still
// be some events in the AWT EventQueue, which need the SolarMutex which
// - on the other hand - is destroyed in DeInitVCL(). So empty the queue
// here ..
if( pSVData->mxAccessBridge.is() )
{
sal_uLong nCount = Application::ReleaseSolarMutex();
pSVData->mxAccessBridge->dispose();
Application::AcquireSolarMutex(nCount);
pSVData->mxAccessBridge.clear();
}
DeInitVCL();
return nReturn;
}
こいつがInitVCLを呼び出してたやつ。
nReturn = pSVData->mpApp->Main();
をnextでとびこえると…あ! LibreOfficeが開いた!
int Desktop::Main()
{
// (長いので略)
}
結局、ここがメインということらしい。ここまで長かった…。
#次回予告
次回はこのMain()
関数をいじって、初めて進捗を生んでみる。
#リンク
##LibreOfficeCalcに関数候補表示機能を付けるまで