oxref(1)

πŸ“¦
version 2.02.00 Β· 4 versions
, in debian trixie, ubuntu questing, ubuntu resolute, ubuntu stonking

🌸 NAME 🌸

okay so bestie, meet oxref(1) β€” the cross reference utility for various languages ✨ she's giving compiler-nerd main character energy and honestly? obsessed.


πŸ’… SYNOPSIS πŸ’…

oxref [OPTIONS] arguments
[OPTIONS] - see the OPTIONS section below
arguments - object files and/or libraries to process

The cross reference listing is written to the standard output stram.

so like, the vibe is: you feed her arguments (object files and/or libraries to process, no cap), you can sprinkle in [OPTIONS] (peep the OPTIONS section below for the whole menu), and the cross reference listing gets written to the standard output stram 🫢


πŸ¦‹ DESCRIPTION πŸ¦‹

oxref generates cross reference listings, program or function call-trees, and/or (recursive) called-by overviews of specified functions, and she does it all using non-stripped object files and/or libraries. no cap. πŸ”₯

Cross reference listings contain the names and source files of functions defined in the specified object files and/or libraries, plus an overview of the functions calling these functions. it's giving receipts for your whole codebase.

Call-trees show the (nested) tree of functions directly or indirectly called from the top-level (main program) function. 🌳

Called-by overviews start from a specified function name, and (recursively) show the functions calling the specified function. literally tracing the group chat back to whoever started it.

Brief examples of these three modes of operation are shown below. πŸ‘‡

Especially the 'called-by' overview is useful information during program development and debugging phases, as it immediately provides the hierarchy of functions directly or indirectly calling the specified function name. ngl this one is the icon, the moment, the whole point.

E.g., assuming that the signature; the pre-conditions or the post-conditions of a function must be changed it is important to know from what function(s) the function-to-modify is called to verify that the changes to the modified function do not break its calling functions. basically: check your callers before you go changing stuff, bestie, or you WILL be the reason the build is crying at 3am 😭

Oxref's output starts with a header showing information about the program, a time stamp and the arguments passed to oxref. E.g., ✨

oxref by Frank B. Brokken (f.b.brokken@rug.nl)
oxref V 2.01.00 2012-2023

CREATED Wed, 25 Oct 2023 11:56:44 +0000
OXREF ARGUMENTS: -t main -r replace -fxs tmp/main.o tmp/libmodules.a
----------------------------------------------------------------------

The header is (depending on the specified options) followed by the cross reference information, the call tree and/or the called-by overview. πŸ’«

Cross reference listings show the symbols, as well as (optionally) their full names (e.g., prefixed by class-names), source files and the source files and names of functions using the symbols. The cross reference listings of a global variable and a function looks like this: πŸ‘‘

    author
      Full name: Icmbuild::author
      Source:    version.cc
      Used By:
        header.cc: header(int, char**)
        usage.cc: usage(std::string const&)

    calledFrom(unsigned long)
      Full name: XrefData::calledFrom(unsigned long)
      Source:    calledfrom.cc
      Used By:
        undefined.cc: Store::undefined(std::string const&)

Call trees show the names of all entities used or called from a certain starting point. For C and C++ programs the starting point main produces the program's full call tree. A (partially shown) call tree might look like this: 🌈

    CALL TREE FOR: main

    main
    +-usage(std::string const&)
    | +-Icmbuild::version
    +-Storage::Storage()
    | +-Store::Store()
    | +-Storage::patternFile(std::string const&)
    +-Storage::tree() const
      +-Store::tree(std::string const&) const
        +-Tree::print(unsigned long, unsigned long)
          +-Tree::calls(unsigned long, unsigned long)
          | +-Tree::calls(unsigned long, XrefData const&)
          +-Tree::indent(unsigned long) const

Calling levels are indented using +- indicators, continuation at identical levels are indicated by vertical lines, using | characters. In the shown call tree main calls usage, the Storage constructor and the Storage::tree() member. Likewise, the Storage constructor calls the Store constructor and the member Storage::patternFile. Recursively called functions appear in the overview where their names are followed by ==> nr arrows where nr refers to the call-level where the function is defined. The top level (e.g. main) is referred to as level 0. Here is an example showing recursion in the call-tree of the bisonc++ program: πŸŒ€

    main
    ...
    +-Grammar::deriveSentence()
    | +-Rules::s_startSymbol
    | +-Grammar::derivable(Symbol const*)
    |   +-Grammar::becomesDerivable(Production const*)
    |   | +-Grammar::derivable(Symbol const*) ==> 2
    |   +-Grammar::isDerivable(Production const*)
    ...

Indirect recursion is shown this way as well. (yes, functions can be their own drama πŸ’€)

Caveat: in order to produce the program's call tree the object file containing the program's starting point (e.g., main) must be available to oxref. If main.o is the object file of the function main then main.o must explicitly be specified as oxref's command-line argument (see, e.g., the command specification shown above in the header line of oxref's output). so like… don't forget to actually hand her main.o, she's not a mind reader bestie πŸ™ˆ

Called-by listings start from a specified function (specified as a regular expression but usually simply specified as ClassName::memberFunction, showing (recursively) the functions calling the specified function (see option --called-by below): πŸŽ€

    CALLED-BY LISTING:

    Store::define(std::string const&, bool) (define.cc): called by
        Store::setFunction(std::string const&) (setfunction.cc)
        Store::setObject(std::string const&) (setobject.cc)
        Store::setSource(std::string const&) (setsource.cc)

    Store::setFunction(std::string const&) (setfunction.cc): called by
        Storage::function(std::string const&) (function.cc)

    Store::setObject(std::string const&) (setobject.cc): called by
        Storage::object(std::string const&) (object.cc)

    Store::setSource(std::string const&) (setsource.cc): called by
        Storage::sourceFile(std::string const&) (sourcefile.cc)

    Storage::function(std::string const&) (function.cc): called by
        Storage::push_back(std::string) (pushback.cc)

    Storage::object(std::string const&) (object.cc): called by
        Storage::push_back(std::string) (pushback.cc)

    Storage::sourceFile(std::string const&) (sourcefile.cc): called by
        Storage::push_back(std::string) (pushback.cc)

    Storage::push_back(std::string) (pushback.cc): called by
        main (main.cc)

⭐ RETURN VALUE ⭐

Oxref returns 1 to the operating system if an error occurs or if oxref automatically shows its usage info. it's giving "something went wrong, here's the manual" energy πŸ’€

Oxref returns 0 if the requested action was successfully completed, or if the --version or --help options are specified. slay, she ate, exit code zero πŸ’–

✨ OPTIONS ✨

Okay bestie, listen up, this is the good part πŸ’… Where it's available, single-letter options are listed in parentheses right after their long-option variants. And heads up: if a long option needs an argument, its single-letter twin needs one too. No exceptions, no cap.

  • --arg=mode (-a) β€” sets how the output gets abbreviated, and mode can be:
    • count β€” function parameters get suppressed entirely, and instead you just see how many arguments the function takes, right there in its parameter list. So like:
usage(1)

instead of

usage(std::string const&)
  • first β€” only the first word of each parameter shows up. Like:
insertDefined(unsigned, std::ostream&, std::vector&)

instead of

insertDefined(unsigned int, std::ostream&,
              std::vector<XrefData,
              std::allocator<XrefData> > const&)
  • len β€” where len is a positive integral number (and if len is less than 5, then 5 gets used instead, periodt). The value len is the maximum length of parameter names. If a name has to get chopped, an ellipsis stands in for the cut-off characters. Example with -a 12:
insertDefined(unsigned int, std::ostream&, std::vect...&)

instead of

insertDefined(unsigned int, std::ostream&,
              std::vector<XrefData,
              std::allocator<XrefData> > const&)
  • --called-by=spec (-c) β€” spec is a regular expression showing (recursively, ooh) the function(s) and the functions calling those functions. Even though spec can point at multiple functions, you can specify a single function like, say, its name prefixed by the function's class. E.g. Store::define β€” which is a member function of oxref's Store class, check the DESCRIPTION section if you need a refresher 🫢.

When you're using the --called-by option, the -f and -s options don't have to be specified. And if you only want the called-by hierarchy, you can throw in --no-xref to stop it from writing the cross-reference listing to the standard output stream.

For example: to generate the called-by listing for oxref's Store::define function, this command was issued:

oxref -Xc Store::define -r replacements tmp/main.o tmp/libmodules.a

(and replacements there is the file holding oxref's type replacements β€” peep the --replace-file option below).

  • --full-symbol (-f) β€” shows the full names of the symbols in addition to the plain symbol names (also go look at the object-files, source-files and xref-source-files options). Full names include class names and/or namespace identifiers. Example:
insertDefined(unsigned int, std::ostream&, std::vector<XrefData,
              std::allocator<XrefData> > const&)
  Full name: Store::insertDefined(unsigned int, std::ostream&,
          std::vector<XrefData, std::allocator<XrefData> > const&)
  • --help (-h) β€” basic usage info gets written to the standard error stream. It's giving helpful ✨
  • --no-xref (-X) β€” stops the cross-reference info from being written to the standard output stream. Lowkey iconic when you're only interested in the program's call-tree (cf. the --tree option).
  • --objdump=command β€” the command value says how the object-dumping program gets called. By default it's called as /usr/bin/objdump -C -t. In practice there's probably no reason to use this option. fr fr.
  • --object-files (-o) β€” includes the names of the object files where symbols (data, functions) are defined in the cross reference listing (also see the full-symbol, source-files and xref-source-files options).
  • --replace=spec (-R) β€” output generated by objdump might show the compiler's ideas of what, like, a C++ std::string is. So instead of a parameter std::sting const & it might show
std::__cxx11::basic_string<char, std::char_traits<char>
                                                        const &

R options are how you specify text replacements, and they look like

#find#replace#

where # can be any character that isn't used in either the find text or the replace text. For example:

#std::__cxx11::basic_string<char, std::char_traits<char>#std::string#

You can specify multiple R options, and they get applied in sequence, line-by-line, to all of objdump's output lines. So like, after you replace that long definition of a string with std::string, any subsequent replacements should use std::string rather than the original long definition the compiler handed you.

In practice you figure out your replacement specs by running oxref without any specs first, and then deriving the replacements you need from the output you got.

  • --replace-file=fname (-r) β€” replacement specs can also live in a file. Specs read from the file get handled just like the ones from replace options, except the replace options get processed before the replacement specs read from the file specified with replace_file. Order matters, bestie πŸ’–
  • --select=name β€” only display the cross-reference of name, where name is the (case sensitive!) initial substring of a symbol.
  • --select-pattern=regex β€” only display the cross-reference of symbols matching the regular expression regex, where regex follows the regex(7) specification, plus the extensions offered by the pattern(3bobcat) Pattern class. Case sensitive matching here too, no exceptions.
  • --source-files (-s) β€” includes the names of the source files where symbols are defined in the cross reference listing (also see the full-symbol, object-files and xref-source-files options).
  • --tree=fname (-t) β€” generates a call tree for function fname. The argument fname is the starting point of the call tree. Quick PSA 🚨: the program's starting point (usually main) doesn't normally show up in a cross-reference listing, because nothing else in the program uses it. So to get the call tree for the program's starting function in those cases, specify --tree main. Otherwise, if you want the call tree of some other function, you have to use its Full name specification exactly as it appears in the cross-reference listing.
  • --xref-source-files (-x) β€” includes the names of the source files where used symbols are defined in the cross reference listing (also see the full-symbol, object-files and source-files options).
  • --version (-v) β€” oxref's version number gets written to the standard error stream.

🌈 EXAMPLES 🌈

These examples show how oxref was called, followed by a representative example of a cross-reference listing for a symbol. Oxref's own cross reference listing was used, cute right?

called as: oxref liboxref

define(std::string const&, bool)
  Used By:
    Store::setFunction(std::string const&)
    Store::setObject(std::string const&)
    Store::setSource(std::string const&)

called as: oxref -foxs liboxref

define(std::string const&, bool)
  Full name: Store::define(std::string const&, bool)
  Source:    define.cc (1define.o)
  Used By:
    setfunction.cc: Store::setFunction(std::string const&)
    setobject.cc: Store::setObject(std::string const&)
    setsource.cc: Store::setSource(std::string const&)

πŸ’€ BUGS πŸ’€

No bugs reported. Not a single one. We stay winning πŸ‘‘


πŸ¦‹ ABOUT πŸ¦‹

In theory, making cross reference listings is a whole complex situation, because it requires a full syntax analysis of the sources that define a program. And especially with complex languages like C++, that's a difficult hurdle to pass. 😭

Searching for cross reference programs with a search engine returns, like, remarkably few hits. LXR is a promising cross referencing program (see http://lxr.linux.no/), but it needs database packages, which makes it kind of a lot to use. Other links just point at cross-reference programs for textual documents, not programs. Not the vibe.

The complexity of building a program that generates a cross reference listing baffled the author for a long time. Eventually the realization hit: in practice, the essential info has already been generated by the compiler when it compiles our source files. So why do it all again? πŸ€”

Once a program's been compiled, one or (usually) more object files are available. The linker uses tables of defined and external symbols embedded in those object files to connect the various functions. If all the requirements can be satisfied, the linker can create a running program.

Programs like nm(1) and objdump(1) can produce human readable output from the info embedded in object files. Oxref reads that info and organizes it, creating a cross reference listing. Iconic behaviour, honestly.

And since all compilable program languages generate identically organized object files (or maybe better: generate object files that objdump(1) can interpret), oxref can broadly be applied. As long as objdump(1) produces sensible output, oxref should be able to generate a cross reference listing. ✨

Oxref's name has two syllables: o and xref. The o represents objdump(1), which oxref calls as a child program. The important part is obviously the cross-referencing of symbols. Like the common abbreviation of rail-road crossing, rail-road xing, cross referencing gets abbreviated to xref. Hence: oxref. 🧠

Of course, nearly everybody will read oxref as ox-ref. Fortunately, here too we're on familiar ground: Bison, Cow, Gnu, Yacc β€” all bovine animals. And to that important list, oxref adds the Ox. πŸ‚πŸ‘‘


πŸŽ€ FILES πŸŽ€

An example of oxref's own cross reference listing is provided (on Debian systems) in the file

/usr/share/doc/oxref/oxref.xref.gz

πŸ”₯ SEE ALSO πŸ”₯

nm(1), objdump(1), pattern(3bobcat), regex(7)


πŸ’œ AUTHOR πŸ’œ

Frank B. Brokken (f.b.brokken@rug.nl).


And that's the whole page, bestie! 🫢 This was oxref version 2.02.00, dated 2012-2024, and it's the oxref(1) manual page. Go forth and cross-reference everything, no cap πŸ’…πŸŒΈ

πŸ“¦ where this page comes from