Created
July 3, 2012 06:43
-
-
Save jessoclarence/3038116 to your computer and use it in GitHub Desktop.
Understanding LibreOffice Source Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Aim | |
To make sense of LibreOffice source code. I plan to put a breakpoint in the constructors of | |
SwTableBox, and then get the back trace to see the flow and gain a little understanding of what's | |
going on. This is post is aimed at beginners, so a little knowledge of C++/Java should be able to | |
get one through this. | |
[A Little Background Info (Skip this) | |
I'm a programmer from the Center for Development of Advanced Computing (CDAC), India, currently | |
on a joint project with King Abdulaziz City for Science and Technology, Saudi Arabia, tasked with | |
fixing bugs/improving LibreOffice. This is part of my efforts to understand (and help my team-mates) | |
the source code. Any comments/suggestions/edits to this will be GREATLY APPRECIATED ;) ] | |
Initial Steps | |
I started to debug LibreOffice by following the steps listed in | |
https://wiki.documentfoundation.org/Development/How_to_debug after creating a build with | |
--enable-debug --enable-symbols set in autogen.sh | |
Starting the Debugger | |
I started soffice with ddd after sourcing ooenv. Next, I set a breakpoint in line 1717 and 1738, | |
constructors of SwTableBox in the file libo/sw/source/core/table/swtable.cxx, by typing | |
"break /home/jesso/Downloads/libreoffice/libo/sw/source/core/table/swtable.cxx:1717", at the | |
GDB console in the bottom of the DDD window, hoping these lines would be executed when a new table | |
was created, and clicked on Run to start the execution. | |
In Writer, I inserted a new table, and as expected, the breakpoint at 1717 was hit! Clicking on | |
Status -> Backtrace in ddd, opens a pop up window with the Backtrace. I am reproducing it below, | |
skipping the memory addresses alone. | |
Backtrace | |
#36 in main () at main.c:24 | |
#35 in sal_main () at main.c:25 | |
#34 in soffice_main () at sofficemain.cxx:77 | |
#33 in SVMain () at svmain.cxx:210 | |
#32 in ImplSVMain () at svmain.cxx:173 | |
#31 in desktop::Desktop::Main () at app.cxx:1764 | |
#30 in Application::Execute () at svapp.cxx:414 | |
#29 in Application::Yield () at svapp.cxx:469 | |
#28 in ImplYield () at svapp.cxx:435 | |
#27 in GtkInstance::Yield () at gtkinst.cxx:538 | |
#26 in GtkData::Yield () at gtkdata.cxx:578 | |
#25 in g_main_context_iteration () from libglib-2.0.so.0 | |
#24 in ?? () from libglib-2.0.so.0 | |
#23 in g_main_context_dispatch () from libglib-2.0.so.0 | |
#22 in ?? from libglib-2.0.so.0 | |
#21 in call_userEventFn () at gtkdata.cxx:950 | |
#20 in GtkData::userEventFn () at gtkdata.cxx:940 | |
#19 in SalGenericDisplay::DispatchInternalEvent () at gendisp.cxx:102 | |
#18 in SalFrame::CallCallback () at salframe.hxx:281 | |
#17 in ImplWindowFrameProc () at winproc.cxx:2575 | |
#16 in ImplHandleUserEvent () at winproc.cxx:2003 | |
#15 in Link::Call () at link.hxx:143 | |
#14 in SfxHintPoster::LinkStubDoEvent_Impl () at hintpost.cxx:65 | |
#13 in SfxHintPoster::DoEvent_Impl () at hintpost.cxx:61 | |
#12 in SfxHintPoster::Event () at hintpost.cxx:71 | |
#11 in GenLink::Call () at genlink.hxx:45 | |
#10 in Link::Call () at link.hxx:143 | |
#09 in SfxDispatcher::LinkStubPostMsgHandler () at dispatch.cxx:1215 | |
#08 in SfxDispatcher::PostMsgHandler () at dispatch.cxx:1244 | |
#07 in SfxDispatcher::Call_impl () at dispatch.cxx:259 | |
#06 in SfxShell::CallExec () at shell.hxx:199 | |
#05 in SfxStubSwTextShellExecInsert () at swslots.hxx:2376 | |
#04 in SwTextShell::ExecInsert () at textsh.cxx:466 | |
#03 in SwBaseShell::InsertTable () at baseh.cxx:2654 | |
#02 in SwEditShell::InsertTable () at edtab.cxx:77 | |
#01 in SwDoc::InsertTable () at ndtbl.cxx:545 | |
#00 in SwTableBox::SwTableBox () at swtable.cxx:1717 | |
What happens in each call | |
I am skipping calls #36 - #25 for now as they are mostly related to application startup. | |
Calls #25 - #22 are inside glib (so, i'm not going to bother much) | |
#25 g_main_context_iteration () from libglib-2.0.so.0 - checks whether any event sources are | |
ready to be processed. More details can be found here at | |
http://developer.gnome.org/glib/2.31/glib-The-Main-Event-Loop.html#g-main-context-iteration | |
#23 in g_main_context_dispatch () from libglib-2.0.so.0 - dispatches all sources. More details | |
are at http://developer.gnome.org/glib/2.31/glib-The-Main-Event-Loop.html#g-main-context-dispatch | |
#21 in call_userEventFn () at gtkdata.cxx:950 - It is called by g_main_context_dispatch () with | |
a pointer to a generic pointer name data. I was unable to dereference it. | |
#20 in GtkData::userEventFn () at gtkdata.cxx:940 - The generic data pointer becomes a GtkData | |
pointer here. Displaying the value pointed to by the pointer reveals a SalGenericData object(?) | |
containing a SalData object (?) and a m_pUserEvent pointer. Dereferencing the m_pUserEvent pointer | |
I found it contained, pointers to callback_funcs, source_funcs, callback_data etc. All these | |
are interesting but I am unable to dereference these now as they are still generic pointer. Well, | |
on the GtkData pointer, GetGtkDisplay() method is called, which returns a GtkSalDisplay object, on | |
which the DispatchInternalEvent() method is called (the method is inherited from SalGenericDisplay). | |
Note - pThis, seems to be concerned with the data directly resulting from the event (?), pData seems | |
to contain the general details of the whole parent window (?), getting it from the GetGenericData() | |
call which returns the variable pImplSVData. | |
#19 in SalGenericDisplay::DispatchInternalEvent () at gendisp.cxx:102 - Here the lock is acquired, | |
to get the values from m_aUserEvents. So, this seems to be where the actual user event and the | |
corresponding data are fetched (?). The nEvent value is 22 (No idea why - is there any mapping to | |
integers and events?). The SalFrame is obtained and the CallCallback method is called on this object. | |
#18 in SalFrame::CallCallback () at salframe.hxx:281 - This just calls the function stored in its | |
own m_pProc variable. | |
#17 in ImplWindowFrameProc () at winproc.cxx:2575 - This contains the message loop. The nEvent = 22 is | |
SALEVENT_USEREVENT. Off we go to the next call in the same file. | |
#16 in ImplHandleUserEvent () at winproc.cxx:1986 - This just calls the function stored in the pointer. | |
#15 in Link::Call () at link.hxx:143 - The function pointed to by the pointer is called. Printing | |
pFunc we get (PSTUB) 0xb758ebbe <SfxHintPoster::LinkStubDoEvent_Impl(void*, void*)> | |
#14 in SfxHintPoster::LinkStubDoEvent_Impl () at /libo/sfx2/source/notify/hintpost.cxx:56 - Simply | |
passes the data along to the next function (?). | |
#13 in in SfxHintPoster::DoEvent_Impl () at /libo/sfx2/source/notify/hintpost.cxx:52 - It passes the | |
pointer it received on to the next function. | |
#12 SfxHintPoster::Event () at hintpost.cxx:60 - I guess now it comes directly here. Seems to | |
pass a function pointer deeper down (phew!). | |
#11 GenLink::Call () at /libo/sfx2/inc/sfx2/genlink.hxx:45 - Calls the function pointer. | |
#10 Link::Call () at /libo/solver/unxlngi6.pro/inc/tools/link.hxx:143 - We've come back (?) to Call #15. | |
It took the else part in the previous call, and we're back. But now we are calling a different function. | |
Printing pFunc here - (PSTUB) 0xb73d97ba <SfxDispatcher::LinkStubPostMsgHandler(void*, void*)> | |
I guess this Link::Call seems to be used to resolve function pointers in general (?). | |
#09 SfxDispatcher::LinkStubPostMsgHandler () at /libo/sfx2/source/control/dispatch.cxx:1205 - | |
This function is commented. (Yay!) Helper method to receive the asynchronously executed <SfxRequest>s. | |
#08 SfxDispatcher::PostMsgHandler () at /libo/sfx2/source/control/dispatch.cxx:1234 - Stuff is added | |
to SfxSlotServer and the next call is made. Expanding the pSlot pointer variable in ddd shows the | |
structure containing variables which have subsequent calls(SfxStubSwTextShellExecInsert) stored in them. | |
#07 in SfxDispatcher::Call_Impl () at /libo/sfx2/source/control/dispatch.cxx:249 - Its a helper | |
function to check whether a slot can be executed and check the execution itself (from the comments in | |
the code). It passes the target function SfxStubSwTextShellExecInsert to method CallExec in class SfxShell. | |
#06 in SfxShell::CallExec () at /libo/sfx2/inc/sfx2/shell.hxx:190 - It simply executes the function | |
pointed to by the function pointer. | |
#05 in SfxStubSwTextShellExecInsert () at /libo/workdir/unxlngi6.pro/SdiTarget/sw/sdi/swslots.hxx:2376, | |
now you'll find a line SFX_EXEC_STUB(SwTextShell,ExecInsert). I spent some time grepping for that, so | |
I'll reproduce that macro here. Btw, macro is defined in 'sfx2/inc/sfx2/msg.hxx'. | |
#define SFX_EXEC_STUB( aShellClass, aExecMethod) \ | |
void SfxStub##aShellClass##aExecMethod( \ | |
SfxShell *pShell, SfxRequest& rReq) \ | |
{ \ | |
(( aShellClass* ) pShell )->aExecMethod( rReq ); \ | |
} | |
IMHO, this file seems to be a gold mine for putting break points, because, like winproc.cxx in #17, | |
all the control seems to flow through these two areas, but I'm not sure about putting breakpoints on | |
macros (?). | |
#04 in SwTextShell::ExecInsert () at /libo/sw/source/ui/shells/textsh.cxx:466 - The code is more | |
understandable at these layers. This function seems to be concerned with the insertion of *all* the | |
objects into the document (is the document itself called as the shell?). It has one huge switch case | |
for handling the various types of objects that can be inserted. Talking about that, the function gets | |
value of the slot from the SfxRequest variable that it received as an argument, whose value the ddd is | |
showing as 20330 (ie. variable nSlot=20330, of type unsigned short), that maps to FN_INSERT_TABLE. | |
How? These details are in /libo/clone/binfilter/binfilter/inc/bf_sw/cmdid.h, in line 349 we have | |
FN_INSERT + 30, and line 38 has FN_INSERT = (SID_SW_START + 300), and SID_SW_START = 20000 (this is | |
defined in /libo/binfilter/inc/bf_sfx2/sfxsids.hrc). So the question becomes, where did it calculate | |
20330 first (got to look keenly in the upper layers and update :( ). Inside the case, it simply calls | |
InsertTable function with the argument that it received. | |
#03 -> SwBaseShell::InsertTable () in libo/sw/source/ui/shells/baseh.cxx:2654 is where all the | |
options entered in the dialog are finally retrieved. The data is present in the _rRequest variable | |
and you can notice the retrieval of the table name, number of rows and columns etc. in lines | |
2582 - 2586, using SFX_REQUEST_ARG macros. The values that are finally stored in pName, pRows etc. | |
were allentered in the Table dialog box, and ddd displays the values as these are ordinary integers. | |
The items are then added once again as to _rRequest in proper Sfx formats(?) in lines 2641 to 2644. | |
Finally at 2654, the table is inserted! Notice that this call is sandwhiched between rSh.StartAllAction () | |
and rSh.EndAllAction (). After this layer, the parameters are passed expicitly, that is, not | |
packaged in SfxRequest object anymore. | |
#02 -> SwEditShell::InsertTable () at libo/sw/source/core/edit/edtab.cxx:77 - Again all the contents of | |
the function are sandwiched between StartAllAction () and EndAllAction (). The current position of the | |
cursor is obtained from GetCrsr()->GetPoint(), and the GetDoc() function seems to return the current | |
document object, on which the next call happens. | |
#01 -> SwDoc::InsertTable () in libo/sw/source/core/docnode/ndtbl.cxx seems to deal at the | |
table level. It gets the boxes/cells from SwTableBox::SwTableBox () and stores it in the | |
variable pBox. It then constructs the table and returns a table node (?) - the variable | |
pNdTbl (of type SwTable). | |
#00 -> SwTableBox::SwTableBox () in libo/sw/source/core/table/swtable.cxx:1717 - This is where I put | |
the break point blindly, well all the constructors in this class had one. This constructor gets called | |
four times, that is, for each cell in the table (am I right about the cell->box mapping?). | |
The journey isn't over yet, the damned table hasn't even been printed to the screen, and every single | |
function has to return the data. I'll edit this again as I make my journey upwards all the way back! | |
Takeaways (Add anything that one can use later) | |
There seem to be a couple of important Get* functions like GetGenericData (), GetDoc (), GetCur () etc. | |
which can be used to get important objects. | |
pImplSVData - seems to be an important variable, used to get the display etc (?). Get it using | |
GetGenericData(). | |
SwWrtShell Object | |
More details about that can be found here http://docs.libreoffice.org/sw/html/classSwWrtShell.html | |
It is used in many functions, and in each case is retrieved by using GetShell (). | |
SfxRequest Object | |
SfxRequest object seems to be a container through which the data are passed around generally. | |
* Items are added to it using, reqObj.AppendItem ( sfx_item ). | |
* After all items are appended method Done() is called on the object. ie. reqObj.Done() | |
* Items are retrieved using SFX_REQUEST_ARG macro. | |
- It is defined in libo/sfx2/inc/sfx2/request.hxx | |
- #define SFX_REQUEST_ARG(rReq, pItem, ItemType, nSlotId, bDeep) \ | |
const ItemType *pItem = (const ItemType*) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment