Someone here already has a nice article on this subject.
No matter, how much people say that ABI compatibility is not something linux kernel developers should be talking about, it is here to stay. Now, why am I talking about ABI when I should be talking about genksyms here ?! Well, because genksyms incidentally is a tiny infamous script that can make the process of ABI tracking so much easier. If the link that I posted above leads you to a long post that's fairly intimidating; fear not, because here's a short description :
genksyms is a small script that calculates checksums of exported symbols which then helps in kernel modversioning i.e Whenever a module is loaded, the checksum of the symbol exported by the kernel and the one that is used by the module can be compared to see if ABI compatibility is maintained. This guarantees a stable running kernel.
All said and done, it's upto you to hack genksyms and make it produce output that suits your need.For example, I formatted the output of genksyms to something (shown below) that can be used effectively to find out all the function signatures that changed between two kernels. I call my exquisite option flag 'l' (for supernatural reasons) and so gcc -E $KERNELDIR/sound/sound_core.c | ./scripts/genksyms/genksyms -l produces :
struct class { UNKNOWN } * sound_class 0xa0b0a8de
int register_sound_special_device ( const struct file_operations { UNKNOWN } * , int , sstruct class { UNKNOWN } * sound_class 0xa0b0a8de
int register_sound_special_device ( const struct file_operations { UNKNOWN } * , int , struct device { UNKNOWN } * ) 0xb8934790
int register_sound_special ( const struct file_operations { UNKNOWN } * , int ) 0xc34bd24d
int register_sound_mixer ( const struct file_operations { UNKNOWN } * , int ) 0x1ee13474
int register_sound_midi ( const struct file_operations { UNKNOWN } * , int ) 0x779fcecd
int register_sound_dsp ( const struct file_operations { UNKNOWN } * , int ) 0x0c7829e0
void unregister_sound_special ( int ) 0x99c95fa5
void unregister_sound_mixer ( int ) 0x7afc9d8a
void unregister_sound_midi ( int ) 0xfdab6de3
void unregister_sound_dsp ( int ) 0xcd083b10
truct device { UNKNOWN } * ) 0xb8934790
int register_sound_special ( const struct file_operations { UNKNOWN } * , int ) 0xc34bd24d
int register_sound_mixer ( const struct file_operations { UNKNOWN } * , int ) 0x1ee13474
int register_sound_midi ( const struct file_operations { UNKNOWN } * , int ) 0x779fcecd
int register_sound_dsp ( const struct file_operations { UNKNOWN } * , int ) 0x0c7829e0
void unregister_sound_special ( int ) 0x99c95fa5
void unregister_sound_mixer ( int ) 0x7afc9d8a
void unregister_sound_midi ( int ) 0xfdab6de3
void unregister_sound_dsp ( int ) 0xcd083b10
If you are wondering WTF is this guy trying to prove, diff-ing the outputs from two different kernel versions will not only show you the cheksums that have changed but will also show why they have changed (in terms of function signatures). That makes the whole thing much transparent.