Question regarding argument types of "BreakpointHitCallback"

Hello,

I would like to ask a question regarding “BreakpointHitCallback”, which is declared as such:

bool (*BreakpointHitCallback)(void *baton,
StoppointCallbackContext *context,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);

Is there any particular reason that “break_id” and “break_loc_id” are of type “user_id_t” (64-bit unsigned) instead of “break_id_t” (32-bit signed), which is used both for “Stoppoint::m_bid” and “StoppointLocation::m_loc_id”?

This causes an issue mainly with internal breakpoints, since the callback of an internal breakpoint with (ID == 0xfffffffe) is called with (break_id == 0xfffffffffffffffe), forcing the callback to cast the argument back to a 32-bit signed in order to use it correctly, e.g. when the IDs are stored and need to be looked up.

A small example attempting to illustrate the problem: https://godbolt.org/z/y8LbK2

― Vangelis

Hello,

I would like to ask a question regarding “BreakpointHitCallback”, which is declared as such:

bool (*BreakpointHitCallback)(void *baton,
StoppointCallbackContext *context,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);

Is there any particular reason that “break_id” and “break_loc_id” are of type “user_id_t” (64-bit unsigned) instead of “break_id_t” (32-bit signed), which is used both for “Stoppoint::m_bid” and “StoppointLocation::m_loc_id”?

I believe this callback predated the time when we added break_id and break_loc_id, and since arguments are part of the signature of C++ functions, we didn’t change it in order to keep the public API from changing. Or this could have just been a mistake. Either way, we have a stable API and can’t really change it.

This causes an issue mainly with internal breakpoints, since the callback of an internal breakpoint with (ID == 0xfffffffe) is called with (break_id == 0xfffffffffffffffe), forcing the callback to cast the argument back to a 32-bit signed in order to use it correctly, e.g. when the IDs are stored and need to be looked up.

A small example attempting to illustrate the problem: https://godbolt.org/z/y8LbK2

Sorry for the issue, but I think we are stuck with it now.

Thank you for the answer, Greg.

I personally managed to work around the problem, although it confused me a bit at first and took a while to figure out the cause. May I suggest the addition of a note in the documentation of “{Breakpoint, Watchpoint}::{Invoke, Set}Callback()” and possibly other relevant functions as a warning to future developers that may stumble upon the same issue?

Regarding the public C++ API, would defining “break_id_t” as “int64_t” be a viable solution or that change would also break the API? It seems that making both types 64-bit alleviates the issue, despite the sign difference.

― Vangelis

Thank you for the answer, Greg.

I personally managed to work around the problem, although it confused me a bit at first and took a while to figure out the cause. May I suggest the addition of a note in the documentation of “{Breakpoint, Watchpoint}::{Invoke, Set}Callback()” and possibly other relevant functions as a warning to future developers that may stumble upon the same issue?

Regarding the public C++ API, would defining “break_id_t” as “int64_t” be a viable solution or that change would also break the API? It seems that making both types 64-bit alleviates the issue, despite the sign difference.

Mangled names don’t encode typedef names, but the bare type. For instance:

cat signatures.cpp
#include <stdint.h>
#include <stdio.h>

typedef int64_t break_id_t;

struct Foo {
void GiveMeABreak(break_id_t id) { printf(“Got: %d\n”, id); }
};

int
main()
{
Foo myFoo;
myFoo.GiveMeABreak(100);
return 0;
}

clang++ -g -O0 signatures.cpp
nm a.out | grep GiveMeABreak
0000000100000f50 T __ZN3Foo12GiveMeABreakEx
c++filt __ZN3Foo12GiveMeABreakEx
Foo::GiveMeABreak(long long)

So this change would change the mangled names of any methods taking a break_id_t, and mean old clients would get missing symbol errors when running with the new API’s. So this isn’t something we can do.

Jim

I understand. Thank you very much for the thorough explanation, Jim! :slightly_smiling_face:

― Vangelis