Firefox reverse engineering via walking the stack

Firefox source is easily available, but too huge to read. So doing a “gdb -p <pid>” to attach to a particular <pid> of the running Firefox process, and issuing “bt”, “rbreak” commands I can walk into different stacktrace – as it revealed the sequence of functions called:
(gdb) bt
#0 0x00007fb313956543 in poll () from /lib/libc.so.6
#1 0x00007fb310c1669e in PollWrapper(_GPollFD*, unsigned int, int) ()
#2 0x00007fb30ea7d4a9 in ?? () from /lib/libglib-2.0.so.0
#3 0x00007fb30ea7d8fc in g_main_context_iteration ()
#4 0x00007fb310c1665f in nsAppShell::ProcessNextNativeEvent(bool) ()
#5 0x00007fb310c2d240 in nsBaseAppShell::OnProcessNextEvent(nsIThreadInternal*, bool, unsigned int) ()
#6 0x00007fb310d93936 in nsThread::ProcessNextEvent(bool, bool*) ()
#7 0x00007fb310d61c59 in NS_ProcessNextEvent_P(nsIThread*, bool) ()
#8 0x00007fb310cd82fb in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) ()
#9 0x00007fb310dc931e in MessageLoop::Run() ()
#10 0x00007fb310c2ccf7 in nsBaseAppShell::Run() ()
#11 0x00007fb310aedbd8 in nsAppStartup::Run() ()
#12 0x00007fb310235fd0 in XREMain::XRE_mainRun() ()
#13 0x00007fb3102331cc in XREMain::XRE_main(int, char**, nsXREAppData const*)
#14 0x00007fb31023332e in XRE_main ()
#15 0x0000000000402709 in main ()

from above….can see many functions too: XRE_main(), nsAppStartup::Run() etc.

First, download the Firefox from nightly built at:

http://nightly.mozilla.org/

and then gdb -p <pid> to attach to the running Firefox process.

Next, “rbreak”:

(gdb) rbreak nsBaseAppShell::*
Breakpoint 1 at 0x7fb310c2cca0
<function, no debug info> nsBaseAppShell::DoProcessMoreGeckoEvents();
Breakpoint 2 at 0x7fb310c2ccac
<function, no debug info> nsBaseAppShell::SuspendNative();
Breakpoint 3 at 0x7fb310c2ccb2
<function, no debug info> nsBaseAppShell::ResumeNative();
Breakpoint 4 at 0x7fb310c2ccb8
<function, no debug info> nsBaseAppShell::GetEventloopNestingLevel(unsigned int*);
Breakpoint 5 at 0x7fb310c2ccca
<function, no debug info> nsBaseAppShell::Run();
Breakpoint 6 at 0x7fb310c2cd10

And then “info breakpoints” to see all the breakpoints set:

(gdb) info breakpoints

Num Type Disp Enb Address What
1 breakpoint keep y 0x00007fb310c2cca0 <nsBaseAppShell::DoProcessMoreGeckoEvents()>
2 breakpoint keep y 0x00007fb310c2ccac <nsBaseAppShell::SuspendNative()>
3 breakpoint keep y 0x00007fb310c2ccb2 <nsBaseAppShell::ResumeNative()>
4 breakpoint keep y 0x00007fb310c2ccb8 <nsBaseAppShell::GetEventloopNestingLevel(unsigned int*)>
5 breakpoint keep y 0x00007fb310c2ccca <nsBaseAppShell::Run()>
6 breakpoint keep y 0x00007fb310c2cd10 <nsBaseAppShell::~nsBaseAppShell()>
7 breakpoint keep y 0x00007fb310c2cd10 <nsBaseAppShell::~nsBaseAppShell()>
8 breakpoint keep y 0x00007fb310c2cd48 <nsBaseAppShell::~nsBaseAppShell()>
9 breakpoint keep y 0x00007fb310c2cd5a <nsBaseAppShell::nsBaseAppShell()>
10 breakpoint keep y 0x00007fb310c2cd5a <nsBaseAppShell::nsBaseAppShell()>
11 breakpoint keep y 0x00007fb310c2cde4 <nsBaseAppShell::DoProcessNextNativeEvent(bool)>
12 breakpoint keep y 0x00007fb310c2ce14 <nsBaseAppShell::RunInStableS---Type <return> to continue, or q <return> to quit---
tate(nsIRunnable*)>
13 breakpoint keep y 0x00007fb310c2ce78 <nsBaseAppShell::Init()>
14 breakpoint keep y 0x00007fb310c2cef0 <nsBaseAppShell::FavorPerformanceHint(bool, unsigned int)>
15 breakpoint keep y 0x00007fb310c2cf30 <nsBaseAppShell::OnDispatchedEvent(nsIThreadInternal*)>
16 breakpoint keep y 0x00007fb310c2cf60 <non-virtual thunk to nsBaseAppShell::OnDispatchedEvent(nsIThreadInternal*)>
17 breakpoint keep y 0x00007fb310c2cf70 <nsBaseAppShell::Exit()>
18 breakpoint keep y 0x00007fb310c2cf96 <nsBaseAppShell::Observe(nsISupports*, char const*, unsigned short const*)>
19 breakpoint keep y 0x00007fb310c2cfc0 <non-virtual thunk to nsBaseAppShell::Observe(nsISupports*, char const*, unsigned short const*)>
20 breakpoint keep y 0x00007fb310c2cfd0 <nsBaseAppShell::QueryInterface(nsID const&, void**)>
21 breakpoint keep y 0x00007fb310c2cff0 <non-virtual thunk to nsBaseAppShell::QueryInterface(nsID const&, void**)>
22 breakpoint keep y 0x00007fb310c2d000 <non-virtual thunk to nsBaseAppShell::QueryInterface(nsID const&, void**)>
23 breakpoint keep y 0x00007fb310c2d010 <nsBaseAppShell::Release()>
24 breakpoint keep y 0x00007fb310c2d040 <non-virtual thunk to nsBaseAppShell::Release()>
25 breakpoint keep y 0x00007fb310c2d050 <non-virtual thunk to nsBaseA---Type <return> to continue, or q <return> to quit---
ppShell::Release()>
26 breakpoint keep y 0x00007fb310c2d060 <nsBaseAppShell::AddRef()>
27 breakpoint keep y 0x00007fb310c2d070 <non-virtual thunk to nsBaseAppShell::AddRef()>
28 breakpoint keep y 0x00007fb310c2d080 <non-virtual thunk to nsBaseAppShell::AddRef()>
breakpoint already hit 1 time
29 breakpoint keep y 0x00007fb310c2d090 <nsBaseAppShell::AfterProcessNextEvent(nsIThreadInternal*, unsigned int)>
30 breakpoint keep y 0x00007fb310c2d0f0 <non-virtual thunk to nsBaseAppShell::AfterProcessNextEvent(nsIThreadInternal*, unsigned int)>
31 breakpoint keep y 0x00007fb310c2d100 <nsBaseAppShell::OnProcessNextEvent(nsIThreadInternal*, bool, unsigned int)>
32 breakpoint keep y 0x00007fb310c2d400 <non-virtual thunk to nsBaseAppShell::OnProcessNextEvent(nsIThreadInternal*, bool, unsigned int)>
33 breakpoint keep y 0x00007fb310c2d410 <nsBaseAppShell::NativeEventCallback()>
34 breakpoint keep y 0x00007fb310c2d4aa <nsBaseAppShell::RunSyncSections()>

Issuing next a sequence of “cont” and “bt” (in succession) I can get the sequence of backtrace functions:

(gdb) bt

#0 0x00007fb310c2d080 in non-virtual thunk to nsBaseAppShell::AddRef() ()
#1 0x00007fb310d9371b in nsThread::PutEvent(nsIRunnable*) ()
#2 0x00007fb310d973fa in nsTimerImpl::PostTimerEvent() ()
#3 0x00007fb310d97f79 in TimerThread::Run() ()
#4 0x00007fb310d93d10 in nsThread::ProcessNextEvent(bool, bool*) ()
#5 0x00007fb310d61c59 in NS_ProcessNextEvent_P(nsIThread*, bool) ()
#6 0x00007fb310d94815 in nsThread::ThreadFunc(void*) ()
#7 0x00007fb3134ebb94 in _pt_root ()
from /home/tthtlc/Downloads/firefox_5may2012_nightly/firefox/libnspr4.so
#8 0x00007fb3147bf9ca in start_thread () from /lib/libpthread.so.0
#9 0x00007fb313962cdd in clone () from /lib/libc.so.6
#10 0x0000000000000000 in ?? ()

And another backtrace (from a different thread btw):

(gdb) bt

#0 0x00007fb310c2cf30 in nsBaseAppShell::OnDispatchedEvent(nsIThreadInternal*) ()
#1 0x00007fb310d93736 in nsThread::PutEvent(nsIRunnable*) ()
#2 0x00007fb310d973fa in nsTimerImpl::PostTimerEvent() ()
#3 0x00007fb310d97f79 in TimerThread::Run() ()
#4 0x00007fb310d93d10 in nsThread::ProcessNextEvent(bool, bool*) ()
#5 0x00007fb310d61c59 in NS_ProcessNextEvent_P(nsIThread*, bool) ()
#6 0x00007fb310d94815 in nsThread::ThreadFunc(void*) ()
#7 0x00007fb3134ebb94 in _pt_root ()
from /home/tthtlc/Downloads/firefox_5may2012_nightly/firefox/libnspr4.so
#8 0x00007fb3147bf9ca in start_thread () from /lib/libpthread.so.0
#9 0x00007fb313962cdd in clone () from /lib/libc.so.6
#10 0x0000000000000000 in ?? ()

To find out the parsing functions:

nm firefox/libxul.so |grep -i parse |grep -i htm

0000000000ba6f60 t _ZThn176_N15HTMLContentSink13OpenContainerERK13nsIParserNode
0000000000ba6310 t _ZThn176_N15HTMLContentSink7AddLeafERK13nsIParserNode
0000000000ba65f0 t _ZThn176_N15HTMLContentSink9SetParserEP12nsParserBase
0000000000ba4f40 t _ZThn176_N15HTMLContentSink9WillParseEv
0000000000d25930 t _ZThn176_N21nsHtml5TreeOpExecutor9SetParserEP12nsParserBase
0000000000d24a10 t _ZThn176_N21nsHtml5TreeOpExecutor9WillParseEv
0000000000ba4730 t _ZThn456_N18nsHTMLVideoElement18GetMozParsedFramesEPj
0000000000cf2b80 t _ZThn8_N13nsHtml5Parser14QueryInterfaceERK4nsIDPPv
0000000000cf2aa0 t _ZThn8_N13nsHtml5Parser6AddRefEv
0000000000cf3010 t _ZThn8_N13nsHtml5Parser7ReleaseEv
0000000000d27160 t _ZThn8_N19nsHtml5StreamParser14QueryInterfaceERK4nsIDPPv
0000000000d27070 t _ZThn8_N19nsHtml5StreamParser6AddRefEv

these are C++ mangled naming convention.

Using a “rbreak nsHtml5Parser” and TAB key, we can get all the names:
nsHtml5Parser::AddRef()
nsHtml5Parser::BeginEvaluatingParserInsertedScript()
nsHtml5Parser::BlockParser()
nsHtml5Parser::BuildModel()
nsHtml5Parser::CanInterrupt()
nsHtml5Parser::CancelParsingEvents()
nsHtml5Parser::ContinueAfterFailedCharsetSwitch()
nsHtml5Parser::ContinueInterruptedParsing()
nsHtml5Parser::ContinueInterruptedParsingAsync()
nsHtml5Parser::DropStreamParser()
nsHtml5Parser::EndEvaluatingParserInsertedScript()
nsHtml5Parser::GetChannel(nsIChannel**)
nsHtml5Parser::GetCommand(nsCString&)
nsHtml5Parser::GetContentSink()
nsHtml5Parser::GetDTD(nsIDTD**)
nsHtml5Parser::GetDocumentCharset(nsACString_internal&, int&)
nsHtml5Parser::GetStreamListener()
nsHtml5Parser::Initialize(nsIDocument*, nsIURI*, nsISupports*, nsIChannel*)
nsHtml5Parser::InitializeDocWriteParserState(nsAHtml5TreeBuilderState*, int)
nsHtml5Parser::IsComplete()
nsHtml5Parser::IsInsertionPointDefined()
nsHtml5Parser::IsParserEnabled()
nsHtml5Parser::IsScriptCreated()
nsHtml5Parser::MarkAsNotScriptCreated(char const*)
nsHtml5Parser::Parse(nsAString_internal const&, void*, nsACString_internal const&, bool, nsDTDMode)
nsHtml5Parser::Parse(nsIURI*, nsIRequestObserver*, void*, nsDTDMode)
nsHtml5Parser::ParseFragment(nsAString_internal const&, nsTArray<nsString, nsTArrayDefaultAllocator>&)
nsHtml5Parser::ParseUntilBlocked()
nsHtml5Parser::QueryInterface(nsID const&, void**)
nsHtml5Parser::QueryInterface(nsID const&, void**)::table
nsHtml5Parser::Release()
nsHtml5Parser::Reset()
nsHtml5Parser::SetCommand(char const*)
nsHtml5Parser::SetCommand(eParserCommands)
nsHtml5Parser::SetContentSink(nsIContentSink*)
nsHtml5Parser::SetDocumentCharset(nsACString_internal const&, int)
nsHtml5Parser::StartTokenizer(bool)
nsHtml5Parser::Terminate()
nsHtml5Parser::UnblockParser()
nsHtml5Parser::_cycleCollectorGlobal
nsHtml5Parser::cycleCollection::Traverse(void*, nsCycleCollectionTraversalCallback&)
nsHtml5Parser::cycleCollection::Unlink(void*)
nsHtml5Parser::cycleCollection::UnmarkIfPurple(nsISupports*)
nsHtml5Parser::nsHtml5Parser()
nsHtml5Parser::operator new(unsigned long)
nsHtml5Parser::~nsHtml5Parser()
nsHtml5ParserThreadTerminator::AddRef()
nsHtml5ParserThreadTerminator::Observe(nsISupports*, char const*, unsigned short const*)
nsHtml5ParserThreadTerminator::QueryInterface(nsID const&, void**)
nsHtml5ParserThreadTerminator::QueryInterface(nsID const&, void**)::table
nsHtml5ParserThreadTerminator::Release()
nsHtml5ParserThreadTerminator::nsHtml5ParserThreadTerminator(nsIThread*)

Doing a breakpoint via “rbreak nsHtml5Parser*” and “cont” and “bt” we get:

#0 0x00007fb310840620 in nsHtml5Parser::operator new(unsigned long) ()
#1 0x00007fb31084071b in nsHtml5Module::NewHtml5Parser() ()
#2 0x00007fb3106cc682 in nsHTMLDocument::StartDocumentLoad(char const*, nsIChannel*, nsILoadGroup*, nsISupports*, nsIStreamListener**, bool, nsIContentSink*) ()
#3 0x00007fb310376651 in nsContentDLF::CreateDocument(char const*, nsIChannel*, nsILoadGroup*, nsISupports*, nsID const&, nsIStreamListener**, nsIContentViewer**) ()
#4 0x00007fb310376bd7 in nsContentDLF::CreateInstance(char const*, nsIChannel*, nsILoadGroup*, char const*, nsISupports*, nsISupports*, nsIStreamListener**, nsIContentViewer**) ()
#5 0x00007fb310a87bde in nsDocShell::NewContentViewerObj(char const*, nsIRequest*, nsILoadGroup*, nsIStreamListener**, nsIContentViewer**) ()
#6 0x00007fb310a942df in nsDocShell::CreateContentViewer(char const*, nsIRequest*, nsIStreamListener**) ()
#7 0x00007fb310a965f5 in nsDSURIContentListener::DoContent(char const*, bool, nsIRequest*, nsIStreamListener**, bool*) ()
#8 0x00007fb310a99116 in nsDocumentOpenInfo::TryContentListener(nsIURIContentListener*, nsIChannel*) ()
#9 0x00007fb310a99342 in nsDocumentOpenInfo::DispatchContent(nsIRequest*, nsISupports*) ()
#10 0x00007fb310a99aef in nsDocumentOpenInfo::OnStartRequest(nsIRequest*, nsISupports*) ()
#11 0x00007fb3102d6f25 in nsHttpChannel::CallOnStartRequest() ()
#12 0x00007fb3102d7331 in nsHttpChannel::ContinueProcessNormal(unsigned int) ()
#13 0x00007fb3102d74bf in nsHttpChannel::ProcessNormal() ()
#14 0x00007fb3102d904e in nsHttpChannel::ProcessResponse() ()
#15 0x00007fb3102d9cc4 in nsHttpChannel::OnStartRequest(nsIRequest*, nsISupports*) ()
#16 0x00007fb310257d0b in nsInputStreamPump::OnStateStart() ()
#17 0x00007fb31025805a in nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream*) ()
#18 0x00007fb310d83732 in nsInputStreamReadyEvent::Run() ()
#19 0x00007fb310d93b23 in nsThread::ProcessNextEvent(bool, bool*) ()
#20 0x00007fb310d61c59 in NS_ProcessNextEvent_P(nsIThread*, bool) ()
#21 0x00007fb310cd82fb in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) ()
#22 0x00007fb310dc931e in MessageLoop::Run() ()
#23 0x00007fb310c2ccf7 in nsBaseAppShell::Run() ()
#24 0x00007fb310aedbd8 in nsAppStartup::Run() ()
#25 0x00007fb310235fd0 in XREMain::XRE_mainRun() () #26 0x00007fb3102331cc in XREMain::XRE_main(int, char**, nsXREAppData const*)
#27 0x00007fb31023332e in XRE_main ()
#28 0x0000000000402709 in main ()

Interesting reverse engineering of Firefox….

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: