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