On Mon, Jul 27, 2020 at 01:59:01PM -0400, y2s1982 via Gcc-patches wrote:
> I do know you have said this several times, and I thought I understood it,
> but it seems I am wrong each time. I just want to clarify my understanding
> and what I had intended on doing on this and would like further explanation
> on what you would like to see happen more specifically so that I may make
> less mistakes.
> 
> My assumption in this patch was that, as the ompd_callback_symbol_addr_fn_t
> callback function takes 2 context addresses and string query as input, and
> ompd_address_t address as an output, I should give it:
>   - the context addresses, which I assumed would contain a single data in
> compact form generated from the tool's side having size, offset, and
> address information,
>   - and a string, which is basically a query that needs to be interpreted
> by the callback function to determine which part of the data it needs to
> use to generate to the returning pointer.

The standard of course can't go into details on what exactly it is, because
it is heavily dependent on what object format is used, etc.
But for ELF, the intent is that the symbol addr callback does pretty much
what dlsym does, i.e. perform a (dynamic) symbol lookup like the dynamic
linker normally performs.  It likely can't use the dynamic linker directly,
for running processes that would mean having to perform an inferior call to
the libdl library, and for core files there is no running process to do it
in, but it knows all the currently loaded libraries, their search order and
so can in that order go one library by one and search their dynamic symbol
tables (if you do nm -D on a library or readelf -Ws, you'll see what is in
there), relocate the addresses in there for shared libraries depending on
their load bias (difference between the addresses they are loaded at and
linked to) and return those.  If filename is supplied, then it would perform
the lookup primarily in the given shared library and only then fallback to
others.

> I wasn't sure what role the filename input played in this.
> This seemed to fit what you meant by having a single compact data that
> contains all the information while resolving my ongoing mystery as to what
> the callback was expecting to have as the string identifying the symbol. To
> further clarify, I assumed the callback would do string manipulation and
> comparison to identify which information is being requested, refer to the
> single data contained in appropriate context, and return the address
> information.
> 
> I am more than willing to scrap my bad idea for a better one. I am
> sincerely interested in learning better ways to implement and improve
> myself. I just need to know more specifics of the design, particularly:
> - where the compact data is stored (I assumed context, which means it might
> not be defined in the library side, but should it be in the handle or
> global to library?),
> - how the information necessary for the compact data is gathered (if it is
> done on the library side, should I just use the ompd_callback_sizeof_fn_t
> to obtain primitive sizes, and from there, just build the offset
> information for each variable members? How about variable address?)
> - how the ompd_callback_symbol_addr_fn_t callback function would likely use
> it given its arguments (input of 2 contexts, 1 file name, 1 string to
> output 1 address),
> - what are the expected strings for the callback that would correspond to
> each variable (here, I assume, the types would be gomp_thread,
> gompd_thread_pool, gomp_team, etc.) or each member of said variables,
> (these, at least I expected, should be documented and agreed on between
> library and tool),
> among other things.

So, there are multiple things you might need to know about the libgomp
shared library's internal ABI in order to implement the OMPD library that
can handle it.
One thing are addresses of internal variables.

Say if OMPD wants to query the value of some ICV, those have different
scopes, some of them are per-process, others per-device, others per-thread,
others per-task.  Say the cancel-var is per process and stored in
gomp_cancel_var which is a bool variable (in env.c).
If you look for that symbol:
readelf -Ws libgomp.so.1 | grep gomp_cancel_var
   478: 0000000000041704     1 OBJECT  LOCAL  DEFAULT   24 gomp_cancel_var
you'll see that there is such a symbol, but it is (intentionally) not
exported and not present in .dynsym, so the symbol lookup callback can't
find it.
So, if OMPD needs to get at the address of that, it again should look at
the single exported variable with all the data and find in it the address
of the variable.  Now, addresses are the only thing which need extra care,
it is something where one needs the help of the assembler and linker.
One way to do it is to have
void *gomp_internal_addresses[] = {
  &gomp_cancel_var,
  ...
};
table and export that.  It is a fallback for when the target can't do
something better, but it will require dynamic relocations, so if possible,
it would be better to use something like:
ptrdiff_t gomp_internal_addr_offsets[] = {
  (char *)&gomp_cancel_var - (char *)&gomp_internal_addr_offsets[0],
  ...
};
which doesn't need dynamic relocations.  All other details, sizeof
something, offsetof (something, field), how many times one needs to
dereference something, or e.g. for the ICVs also the information whether
the ICV lives in a per-process variable (which), or is e.g. at some offset
in the gomp_thread or where exactly, is something I'd highly suggest
to initially just hardcode in the ompd source with some specific comment
above it, so that you can then very quickly find everything that initially
non-portably is hardcoded in libgompd.so.1 and thus e.g. it can't support
-m32 vs. -m64, and only after you get a better picture of what exactly you
need you start putting it into the compact data section.

So, say you start with libgompd.so.1 sources doing:
          /* INFO */
  addr += offsetof (struct blah, field);
and once you have big part of OMPD implemented, you go through everything
you have such comments on, and instead create ompd-info-generate.c
to contain some macros that in the end will store the offsetof value in the
output and then on the libgompd.so.1 part read that back.

        Jakub

Reply via email to