fsa.gplok = gplok;
fsa.warn = warn;
//Find the symbol and fill in the output part of the symbol parameter structure
if (each_symbol_section(find_symbol_in_section, &fsa)) {
if (owner) //NULL, no value is required below
*owner = fsa.owner;
if (crc) //Get the crc value of the symbol
*crc = fsa.crc;
//Return the kernel symbol structure named by name
return fsa.sym;
}
//No kernel symbol found, return NULL
pr_debug("Failed to find symbol %sn", name);
return NULL;
}
bool each_symbol_section(bool (*fn)(const struct symsearch *arr,struct module *owner,void *data),void *data)
{
struct module *mod;
//The first part searches for the corresponding symbol in the symbol table exported by the kernel. If found, the corresponding symbol information is returned. Otherwise, the second part searches again.
/*struct symsearch {
const struct kernel_symbol *start, *stop;
const unsigned long *crcs;
enum {
NOT_GPL_ONLY,
GPL_ONLY,
WILL_BE_GPL_ONLY,
}licence;
bool unused;
};
*/
static const struct symsearch arr[] = {
{ __start___ksymtab, __stop___ksymtab,
__start___kcrctab,NOT_GPL_ONLY, false },
{ __start___ksymtab_gpl, __stop___ksymtab_gpl,
__start___kcrctab_gpl,GPL_ONLY, false },
{ __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
__start___kcrctab_gpl_future,WILL_BE_GPL_ONLY, false },
#ifdef CONFIG_UNUSED_SYMBOLS
{ __start___ksymtab_unused, __stop___ksymtab_unused,
__start___kcrctab_unused,NOT_GPL_ONLY, true },
{ __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
__start___kcrctab_unused_gpl,GPL_ONLY, true },
#endif
};
if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
return true;
//If the corresponding symbol is not found in the symbol table exported by the kernel, search in the modules loaded by the system
list_for_each_entry_rcu(mod, &modules, list) {
struct symsearch arr[] = {
{ mod->syms, mod->syms + mod->num_syms,
mod->crcs,NOT_GPL_ONLY, false },
{ mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
mod->gpl_crcs,GPL_ONLY, false },
{ mod->gpl_future_syms,mod->gpl_future_syms + mod->num_gpl_future_syms,
mod->gpl_future_crcs,WILL_BE_GPL_ONLY, false },
#ifdef CONFIG_UNUSED_SYMBOLS
{ mod->unused_syms,mod->unused_syms + mod->num_unused_syms,
mod->unused_crcs, NOT_GPL_ONLY, true },
{ mod->unused_gpl_syms,mod->unused_gpl_syms + mod->num_unused_gpl_syms,
mod->unused_gpl_crcs,GPL_ONLY, true },
#endif
};
//If the module state is MODULE_STATE_UNFORMED, the symbols of this module are not available
if (mod->state == MODULE_STATE_UNFORMED)
continue;
if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data))
return true;
}
return false;
}
static bool each_symbol_in_section(const struct symsearch *arr,unsigned int arrsize,struct module *owner,bool (*fn)(const struct symsearch *syms,struct module *owner,void *data),void *data)
{
unsigned int j;
//Call find_symbol_in_section() to search the symbol address range specified by each array
for (j = 0; j < arrsize; j++) {
if (fn(&arr[j], owner, data))//Call find_symbol_in_section()
return true;
}
return false;
}
static bool find_symbol_in_section(const struct symsearch *syms,struct module *owner,void *data)
{
struct find_symbol_arg *fsa = data;
struct kernel_symbol *sym;
//Search for kernel symbols with symbol name fsa->name in the range
sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,sizeof(struct kernel_symbol), cmp_name);
//If the kernel symbol is found, check whether it is valid
if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data))
return true;
return false;
}
void *bsearch(const void *key, const void *base, size_t num, size_t size,int (*cmp)(const void *key, const void *elt))
{
size_t start = 0, end = num;
int result;
while (start < end) {//binary search
size_t mid = start + (end - start) / 2;
//Call cmp_name() function to compare whether the symbol name is consistent
result = cmp(key, base + mid * size);
if (result < 0)
end = mid;
else if (result > 0)
start = mid + 1;
else
return (void *)base + mid * size;
}
return NULL;
}
static int cmp_name(const void *va, const void *vb)
{
const char *a;
const struct kernel_symbol *b;
a = va; b = vb;
return strcmp(a, b->name);
}
static bool check_symbol(const struct symsearch *syms,struct module *owner,unsigned int symnum, void *data)
{
struct find_symbol_arg *fsa = data;
if (!fsa->gplok) { //If gplok is not set, it must be GPL licensed
if (syms->licence == GPL_ONLY)
return false;
if (syms->licence == WILL_BE_GPL_ONLY && fsa->warn) {
printk(KERN_WARNING "Symbol %s is being used "
"by a non-GPL module, which will not "
"be allowed in the future", fsa->name);
}
}
#ifdef CONFIG_UNUSED_SYMBOLS
if (syms->unused && fsa->warn) {
printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
"however this module is using it.n", fsa->name);
printk(KERN_WARNING"This symbol will go away in the future.n");
printk(KERN_WARNING
"Please evalute if this is the right api to use and if "
"it really is, submit a report the linux kernel "
"mailinglist together with submitting your code for "
"inclusion.n");
}
#endif
fsa->owner = owner; //Symbol belongs to the module
//#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
fsa->crc = symversion(syms->crcs, symnum); // CRC value of the symbol
fsa->sym = &syms->start[symnum]; //Returned symbol structure
return true;
}
static int check_version(Elf_Shdr *sechdrs,unsigned int versindex,const char *symname,struct module *mod, const unsigned long *crc,const struct module *crc_owner)
{
unsigned int i, num_versions;
struct modversion_info *versions;
//If the crc value of the symbol in the system is 0, return 1 directly.
if (!crc)
return 1;
//If there is no __versions section in the elf format file of the module, try to force load the module
//However, the implementation of the try_to_force_load() function depends on whether the CONFIG_MODULE_FORCE_LOAD macro is defined. This macro is not defined by default, so failure will be returned here. It seems that the kernel does not recommend forced module loading.
if (versindex == 0)
return try_to_force_load(mod, symname) == 0;
//Find the starting address of the module "__versions" section in the memory image. Equivalent to the contents of the section
versions = (void *) sechdrs[versindex].sh_addr;
num_versions = sechdrs[versindex].sh_size/ sizeof(struct modversion_info);
for (i = 0; i < num_versions; i++) {
if (strcmp(versions[i].name, symname) != 0) // Find the symbol to be compared in this section
continue;
//Compare the CRC value of the symbol in the module with the CRC value of the kernel symbol on the current system to see if they are consistent
if (versions[i].crc == maybe_relocated(*crc, crc_owner))
return 1;
pr_debug("Found checksum %lX vs module %lXn",maybe_relocated(*crc, crc_owner), versions[i].crc);
goto bad_version;
}
//If the symbol to be compared is not found in the "__versions" section, a common error when loading a module will be given: "no symbol version for"
printk(KERN_WARNING "%s: no symbol version for %sn",mod->name, symname);
return 0;
bad_version:
//If the CRC values of the comparison symbols are inconsistent, a common error when loading modules will be given: "disagrees about version of symbol"
printk("%s: disagrees about version of symbol %sn",mod->name, symname);
return 0;
}
static int try_to_force_load(struct module *mod, const char *reason)
{
#ifdef CONFIG_MODULE_FORCE_LOAD
//If option CONFIG_MODULE_FORCE_LOAD is on, check if tainted_mask has the TAINT_FORCED_MODULE flag set, if not give a warning message
if (!test_taint(TAINT_FORCED_MODULE))
printk(KERN_WARNING "%s: %s: kernel tainted.n",mod->name, reason);
//Set the TAINT_FORCED_MODULE flag of mod->taints and tainted_mask to force the module to load and return the correct value 0
add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_NOW_UNRELIABLE);
return 0;
#else
//If the option CONFIG_MODULE_FORCE_LOAD is not enabled, an error is returned directly
return -ENOEXEC;
#endif
}
static int check_modinfo(struct module *mod, struct load_info *info, int flags)
{
//Get the version magic from the module .modinfo section
const char *modmagic = get_modinfo(info, "vermagic");
int err;
if (flags & MODULE_INIT_IGNORE_VERMAGIC)
modmagic = NULL;
//If version magic is 0, try to force load
if (!modmagic) {
err = try_to_force_load(mod, "bad vermagic");
if (err)
return err;
}
// Is it consistent with the kernel's vermagic? If not, give the famous error: "version magic ... should be ..." and return the error code
else if (!same_magic(modmagic, vermagic, info->index.vers)) {
printk(KERN_ERR "%s: version magic '%s' should be '%s'n",mod->name, modmagic, vermagic);
return -ENOEXEC;
}
//Return the content of intree="..." in the .modinfo section. If it does not exist, set the flag TAINT_OOT_MODULE
if (!get_modinfo(info, "intree"))
add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
//Return the content of staging="..." in the .modinfo section, if there is a flag set TAINT_CRAP
if (get_modinfo(info, "staging")) {
add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);
printk(KERN_WARNING "%s: module is from the staging directory,"" the quality is unknown, you have been warned.n",mod->name);
Previous article:Linux driver to create a hello module
Next article:S3C2440 Watchdog Timer Principle
Recommended ReadingLatest update time:2024-11-16 20:40
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Conformal Array for Radar Missile Seeker
- TMS570LS1224_GY30 light sensor driver
- Good information on clock division
- A question about the STM32L073 port A driver
- 【Gravity:AS7341 Review】Color Temperature Perception Measurement: Analysis of Three Chip Performance
- Problems with devices that measure temperature
- Huawei Science Comic: How do Bluetooth, Wi-Fi, and GNSS work together? Connectivity Chip
- InstaSPIN Brushless DC (BLDC) Lab
- [Synopsys IP Resources] How to cope with the challenges of HPC SoC development in the era of surging data volume
- Discussion on the selection of charging management IC with path management