Re: break on C++ global objects ctors

Daniel Gutson
2014-09-26T18:00:07Z

[-- Attachment #1: Type: text/plain, Size: 3623 bytes --]

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

[-- Attachment #2: BreakAtGlobals.py --]
[-- Type: text/x-python, Size: 3085 bytes --]

# 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