This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: break on C++ global objects ctors
- From: Daniel Gutson <daniel dot gutson at tallertechnologies dot com>
- To: Paul_Koning at dell dot com
- Cc: gdb-patches <gdb-patches at sourceware dot org>, Martin Galvan <martin dot galvan at tallertechnologies dot com>
- Date: Fri, 26 Sep 2014 15:00:02 -0300
- Subject: Re: break on C++ global objects ctors
- Authentication-results: sourceware.org; auth=none
- References: <CAF5HaEU_5DhgydC0B7Ucx+owH3+PqsztZphAARzc80+9VBBtBA at mail dot gmail dot com> <CAF5HaEU3nmr9Ak5dGByUPfe0JGn4NwHu_5JUpB7Fsn6CjfuzOw at mail dot gmail dot com> <C75A84166056C94F84D238A44AF9F6AD16C9B3FB at AUSX10MPC103 dot AMER dot DELL dot COM> <CAF5HaEW8iNZHEx+SA=MBu26XMZO+ENwqXhoJwLtZSMCHc_jNcA at mail dot gmail dot com> <C75A84166056C94F84D238A44AF9F6AD16C9B531 at AUSX10MPC103 dot AMER dot DELL dot COM> <CAF5HaEV8mKgasabcnyDjZN4aT6U=Oj4Yh9tiryUYyPr-Z+13Cw at mail dot gmail dot com>
I resurrect this issue since there was no satisfying solution.
We went through the plugin solution, just to check the idea, and maybe
later discuss a native
(maybe gdb-gcc joint) solution.
There were three possible approaches:
- a regex-based approach, library-implementation independent, so the
plugin does some magic looking for symbols and detecting which one
have, placing breakpoints there, breaking at main and add a command in
main to disable all the previous breakpoints. The attached file is a
plugin that follows this approach.
- a library-implementation dependent approach, that breaks in all
the __static_initialization_and_destruction_0, then disassemblying
them finding each call to a ctor, placing a breakpoint there with a
"stepi" command. We are tempted to follow this approach but we ran out
of time so we're using the previous one. And we don't know how
portable this is (we checked x86 but need this tool for a number of
other platforms, such as ARM and SPARC). I believe that
__static_initialization_and_destruction_0 is generated for all
platforms and with the same name but I'm not sure.
- a dwarf-inspection based approach which we didn't deeply explore.
Now, the plugin isn't perfect, has some corner cases, and required a
huge amount of regex magic (specially due to C++ templates).
Is there consensus that this could be done in a native command, such
as "break-global-ctors" (and "break-global-dtors", which the plugin
doesn't address either) ?
Thanks,
Daniel.
ps: BTW, we found a lot of opportunities to improve of the python API
that would make this plugin much simpler, but that will go to a
separate thread.
On Mon, Mar 31, 2014 at 11:41 AM, Daniel Gutson
<daniel.gutson@tallertechnologies.com> wrote:
> On Mon, Mar 31, 2014 at 11:15 AM, <Paul_Koning@dell.com> wrote:
>>
>> On Mar 31, 2014, at 10:10 AM, Daniel Gutson <daniel.gutson@tallertechnologies.com> wrote:
>>
>>> On Mon, Mar 31, 2014 at 10:56 AM, <Paul_Koning@dell.com> wrote:
>>>> This certainly should be easily doable, just in gdb. FWIW, if you start a program with gdbserver and then connect to it from gdb ("target remote" to gdbserver), the program is stopped at the first instruction, way before "main".
>>>
>>> That doesn't solve how gdb detects the beginning of each ctor function.
>>
>> I don't know what problem you're referring to. A constructor is just a function, which has a name, and you can set a breakpoint on it.
>>
>> If for some reason that's not working, that would be a bug, but I've used breakpoints on constructors for a long time and it seems to work when I try it.
>
> The issue I need to add is to make gdb break at the beginning of the
> construction of each (all) global object of the program.
> Breaking at the beginning of the program does not solve this. Please
> see my original with this clarification, so maybe I can be clearer.
>
> One possible solution is: add breaks in the ctors of ALL types, run,
> and at main delete all those breakpoints.
> Another solution is to do some handling of each
> __static_initialization_and_destruction_0 which varies depending on
> the context.
>
>
>>
>> paul
>
>
>
> --
>
> Daniel F. Gutson
> Chief Engineering Officer, SPD
>
>
> San Lorenzo 47, 3rd Floor, Office 5
>
> CÃrdoba, Argentina
>
>
> Phone: +54 351 4217888 / +54 351 4218211
>
> Skype: dgutson
--
Daniel F. Gutson
Chief Engineering Officer, SPD
San Lorenzo 47, 3rd Floor, Office 5
CÃrdoba, Argentina
Phone: +54 351 4217888 / +54 351 4218211
Skype: dgutson
# BreakAtGlobals.py: A GDB script for setting breakpoints at global constructors.
#
# Copyright (C) 2014 Martin Galvan, Daniel Gutson, Taller Technologies.
#
# BreakAtGlobals is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BreakAtGlobals is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BreakAtGlobals. If not, see <http://www.gnu.org/licenses/>.
import re
import gdb
class MainBreakpoint(gdb.Breakpoint):
def stop(self):
for breakpointNumber in range(1, self.number):
gdb.execute("delete " + str(breakpointNumber))
return False
def breakAtGlobals():
gdb.execute("set confirm off")
gdb.execute("set pagination off")
gdb.execute("set logging overwrite on")
gdb.execute("set logging file breakAtGlobalsTmp.txt")
gdb.execute("set logging redirect on")
gdb.execute("set logging on")
gdb.execute("info types")
gdb.execute("set logging off")
with open("breakAtGlobalsTmp.txt", "r") as outputLog:
typeNames = getTypes(outputLog)
constructors = getConstructors(typeNames)
for constructor in constructors:
gdb.execute("rbreak " + constructor + "*")
MainBreakpoint("main")
def getTypes(outputLog):
definedTypes = set()
typeNames = []
skipNextLine = True # Skip the first line.
for line in outputLog:
if skipNextLine:
skipNextLine = False
elif line == "\n": # An empty line is always followed by a useless line. Skip it.
skipNextLine = True
elif "typedef" not in line: # This line contains a type name. Skip typedefs.
definedTypes.add(line.rstrip(";\n"))
for definedType in definedTypes:
gdbType = gdb.types.get_basic_type(gdb.lookup_type(definedType))
typeNames.append(gdbType.name)
return typeNames
def getConstructors(typeNames):
constructors = []
finalConstructors = []
# Append the class name to the type.
for typeName in typeNames:
if "::" in typeName: # Our type is inside a namespace. Extract the class name from the full type name.
className = typeName.rpartition("::")[2]
else:
className = typeName
constructors.append(typeName + "::" + className)
for constructor in constructors:
finalConstructors.append(removeTemplateArguments(constructor))
return finalConstructors
# Template classes have a <(some type)> at the end.
def removeTemplateArguments(constructor):
match = None
for match in re.finditer("(<.*?>)", constructor):
pass
if match:
constructor = constructor[:match.start()]
return constructor