Messages in this thread | | | From | Keith Owens <> | Subject | Kernel flow graphing (was Re: Take a deep breath...) | Date | Wed, 16 Jul 1997 21:40:11 +1000 |
| |
On 15 Jul 1997 19:44:43 +0300, Kohtala Marko <Marko.Kohtala@ntc.nokia.com> wrote: >I have been playing with an idea of adding some LClint directives into >linux source and perhaps extending LClint to provide some additional >information about the source code (call graphs, uses of structures, >uses of structure members, ranges of values used).
FWIW, some time ago I wrote perl code that took the output from "cflow -axg <filename(s)>" and generated commands to a compiler visulation tool (xvcg). The aim was to do part of what you suggested, determine the call graphs. Unfortunately even something as "small" as net/ipv4/*.[ch] generated a very wide, very flat graph. It was not more than 6 levels deep but was about 50 functions wide. Took up a lot of room on the wall :).
Add to that the fact that so many of the higher level functions are not called directly but instead are called via pointers from structures and it becomes very difficult to automatically graph the function flow.
Take function ipfw_device_event in ipv4/ip_fw.c (2.1.44). The only reference to that is in structure ipfw_dev_notifier in the same source. The structure is passed to register_netdevice_notifier in core/dev.c which in turn calls notifier_chain_register. notifier_chain_register is an inline macro in linux/notifier.h, with the parameters from register_netdevice_notifier it adds ipfw_device_event to the netdev_chain. Functions on the netdev_chain are invoked via notifier_call_chain (another inline macro) from 5 places in core/dev.c and 3 places in ipv4/devinet.c.
To a human, all the above means that ipfw_device_event is called when any network device comes up, goes down, changes address, changes MTU or changes some interface flags. However no tool like lint or cflow has any hope of tracking that depth of function flow with all the indirection that goes on. Flow within a module can be done but not across modules.
I suspect the real answer is the equivalent of short man pages for each high level function. Something like :-
int register_netdevice_notifier(struct notifier_block *nb)
Adds the function in field nb->notifier_call to the netdev_chain. Functions on this chain will be called for events NETDEV_UP, NETDEV_DOWN, NETDEV_CHANGE, NETDEV_CHANGEMTU, NETDEV_CHANGEADDR. See function notifier_call_chain for return code handling of called functions.
register_netdevice_notifier return code: Always 0, see notifier_chain_register.
int ipfw_device_event(struct notifier_block *this, unsigned long event, void *ptr)
Called via notifier_call_chain on netdev_chain (see register_netdevice_notifier). Entered in any state. Disables interrupts to update the device information in the firewall chains for NETDEV_UP and NETDEV_DOWN. Restores initial state on exit.
ipfw_device_event return code: Always NOTIFY_DONE.
Best place is probably in the source, even though that will increase the tar ball size. Some sort of standard format that can be extracted and printed or converted to HTML.
| |