1*ac7bd094SKris Van Hees#!/usr/bin/gawk -f 2*ac7bd094SKris Van Hees# SPDX-License-Identifier: GPL-2.0 3*ac7bd094SKris Van Hees# verify_builtin_ranges.awk: Verify address range data for builtin modules 4*ac7bd094SKris Van Hees# Written by Kris Van Hees <[email protected]> 5*ac7bd094SKris Van Hees# 6*ac7bd094SKris Van Hees# Usage: verify_builtin_ranges.awk modules.builtin.ranges System.map \ 7*ac7bd094SKris Van Hees# modules.builtin vmlinux.map vmlinux.o.map 8*ac7bd094SKris Van Hees# 9*ac7bd094SKris Van Hees 10*ac7bd094SKris Van Hees# Return the module name(s) (if any) associated with the given object. 11*ac7bd094SKris Van Hees# 12*ac7bd094SKris Van Hees# If we have seen this object before, return information from the cache. 13*ac7bd094SKris Van Hees# Otherwise, retrieve it from the corresponding .cmd file. 14*ac7bd094SKris Van Hees# 15*ac7bd094SKris Van Heesfunction get_module_info(fn, mod, obj, s) { 16*ac7bd094SKris Van Hees if (fn in omod) 17*ac7bd094SKris Van Hees return omod[fn]; 18*ac7bd094SKris Van Hees 19*ac7bd094SKris Van Hees if (match(fn, /\/[^/]+$/) == 0) 20*ac7bd094SKris Van Hees return ""; 21*ac7bd094SKris Van Hees 22*ac7bd094SKris Van Hees obj = fn; 23*ac7bd094SKris Van Hees mod = ""; 24*ac7bd094SKris Van Hees fn = substr(fn, 1, RSTART) "." substr(fn, RSTART + 1) ".cmd"; 25*ac7bd094SKris Van Hees if (getline s <fn == 1) { 26*ac7bd094SKris Van Hees if (match(s, /DKBUILD_MODFILE=['"]+[^'"]+/) > 0) { 27*ac7bd094SKris Van Hees mod = substr(s, RSTART + 16, RLENGTH - 16); 28*ac7bd094SKris Van Hees gsub(/['"]/, "", mod); 29*ac7bd094SKris Van Hees } else if (match(s, /RUST_MODFILE=[^ ]+/) > 0) 30*ac7bd094SKris Van Hees mod = substr(s, RSTART + 13, RLENGTH - 13); 31*ac7bd094SKris Van Hees } else { 32*ac7bd094SKris Van Hees print "ERROR: Failed to read: " fn "\n\n" \ 33*ac7bd094SKris Van Hees " For kernels built with O=<objdir>, cd to <objdir>\n" \ 34*ac7bd094SKris Van Hees " and execute this script as ./source/scripts/..." \ 35*ac7bd094SKris Van Hees >"/dev/stderr"; 36*ac7bd094SKris Van Hees close(fn); 37*ac7bd094SKris Van Hees total = 0; 38*ac7bd094SKris Van Hees exit(1); 39*ac7bd094SKris Van Hees } 40*ac7bd094SKris Van Hees close(fn); 41*ac7bd094SKris Van Hees 42*ac7bd094SKris Van Hees # A single module (common case) also reflects objects that are not part 43*ac7bd094SKris Van Hees # of a module. Some of those objects have names that are also a module 44*ac7bd094SKris Van Hees # name (e.g. core). We check the associated module file name, and if 45*ac7bd094SKris Van Hees # they do not match, the object is not part of a module. 46*ac7bd094SKris Van Hees if (mod !~ / /) { 47*ac7bd094SKris Van Hees if (!(mod in mods)) 48*ac7bd094SKris Van Hees mod = ""; 49*ac7bd094SKris Van Hees } 50*ac7bd094SKris Van Hees 51*ac7bd094SKris Van Hees gsub(/([^/ ]*\/)+/, "", mod); 52*ac7bd094SKris Van Hees gsub(/-/, "_", mod); 53*ac7bd094SKris Van Hees 54*ac7bd094SKris Van Hees # At this point, mod is a single (valid) module name, or a list of 55*ac7bd094SKris Van Hees # module names (that do not need validation). 56*ac7bd094SKris Van Hees omod[obj] = mod; 57*ac7bd094SKris Van Hees 58*ac7bd094SKris Van Hees return mod; 59*ac7bd094SKris Van Hees} 60*ac7bd094SKris Van Hees 61*ac7bd094SKris Van Hees# Return a representative integer value for a given hexadecimal address. 62*ac7bd094SKris Van Hees# 63*ac7bd094SKris Van Hees# Since all kernel addresses fall within the same memory region, we can safely 64*ac7bd094SKris Van Hees# strip off the first 6 hex digits before performing the hex-to-dec conversion, 65*ac7bd094SKris Van Hees# thereby avoiding integer overflows. 66*ac7bd094SKris Van Hees# 67*ac7bd094SKris Van Heesfunction addr2val(val) { 68*ac7bd094SKris Van Hees sub(/^0x/, "", val); 69*ac7bd094SKris Van Hees if (length(val) == 16) 70*ac7bd094SKris Van Hees val = substr(val, 5); 71*ac7bd094SKris Van Hees return strtonum("0x" val); 72*ac7bd094SKris Van Hees} 73*ac7bd094SKris Van Hees 74*ac7bd094SKris Van Hees# Determine the kernel build directory to use (default is .). 75*ac7bd094SKris Van Hees# 76*ac7bd094SKris Van HeesBEGIN { 77*ac7bd094SKris Van Hees if (ARGC < 6) { 78*ac7bd094SKris Van Hees print "Syntax: verify_builtin_ranges.awk <ranges-file> <system-map>\n" \ 79*ac7bd094SKris Van Hees " <builtin-file> <vmlinux-map> <vmlinux-o-map>\n" \ 80*ac7bd094SKris Van Hees >"/dev/stderr"; 81*ac7bd094SKris Van Hees total = 0; 82*ac7bd094SKris Van Hees exit(1); 83*ac7bd094SKris Van Hees } 84*ac7bd094SKris Van Hees} 85*ac7bd094SKris Van Hees 86*ac7bd094SKris Van Hees# (1) Load the built-in module address range data. 87*ac7bd094SKris Van Hees# 88*ac7bd094SKris Van HeesARGIND == 1 { 89*ac7bd094SKris Van Hees ranges[FNR] = $0; 90*ac7bd094SKris Van Hees rcnt++; 91*ac7bd094SKris Van Hees next; 92*ac7bd094SKris Van Hees} 93*ac7bd094SKris Van Hees 94*ac7bd094SKris Van Hees# (2) Annotate System.map symbols with module names. 95*ac7bd094SKris Van Hees# 96*ac7bd094SKris Van HeesARGIND == 2 { 97*ac7bd094SKris Van Hees addr = addr2val($1); 98*ac7bd094SKris Van Hees name = $3; 99*ac7bd094SKris Van Hees 100*ac7bd094SKris Van Hees while (addr >= mod_eaddr) { 101*ac7bd094SKris Van Hees if (sect_symb) { 102*ac7bd094SKris Van Hees if (sect_symb != name) 103*ac7bd094SKris Van Hees next; 104*ac7bd094SKris Van Hees 105*ac7bd094SKris Van Hees sect_base = addr - sect_off; 106*ac7bd094SKris Van Hees if (dbg) 107*ac7bd094SKris Van Hees printf "[%s] BASE (%s) %016x - %016x = %016x\n", sect_name, sect_symb, addr, sect_off, sect_base >"/dev/stderr"; 108*ac7bd094SKris Van Hees sect_symb = 0; 109*ac7bd094SKris Van Hees } 110*ac7bd094SKris Van Hees 111*ac7bd094SKris Van Hees if (++ridx > rcnt) 112*ac7bd094SKris Van Hees break; 113*ac7bd094SKris Van Hees 114*ac7bd094SKris Van Hees $0 = ranges[ridx]; 115*ac7bd094SKris Van Hees sub(/-/, " "); 116*ac7bd094SKris Van Hees if ($4 != "=") { 117*ac7bd094SKris Van Hees sub(/-/, " "); 118*ac7bd094SKris Van Hees mod_saddr = strtonum("0x" $2) + sect_base; 119*ac7bd094SKris Van Hees mod_eaddr = strtonum("0x" $3) + sect_base; 120*ac7bd094SKris Van Hees $1 = $2 = $3 = ""; 121*ac7bd094SKris Van Hees sub(/^ +/, ""); 122*ac7bd094SKris Van Hees mod_name = $0; 123*ac7bd094SKris Van Hees 124*ac7bd094SKris Van Hees if (dbg) 125*ac7bd094SKris Van Hees printf "[%s] %s from %016x to %016x\n", sect_name, mod_name, mod_saddr, mod_eaddr >"/dev/stderr"; 126*ac7bd094SKris Van Hees } else { 127*ac7bd094SKris Van Hees sect_name = $1; 128*ac7bd094SKris Van Hees sect_off = strtonum("0x" $2); 129*ac7bd094SKris Van Hees sect_symb = $5; 130*ac7bd094SKris Van Hees } 131*ac7bd094SKris Van Hees } 132*ac7bd094SKris Van Hees 133*ac7bd094SKris Van Hees idx = addr"-"name; 134*ac7bd094SKris Van Hees if (addr >= mod_saddr && addr < mod_eaddr) 135*ac7bd094SKris Van Hees sym2mod[idx] = mod_name; 136*ac7bd094SKris Van Hees 137*ac7bd094SKris Van Hees next; 138*ac7bd094SKris Van Hees} 139*ac7bd094SKris Van Hees 140*ac7bd094SKris Van Hees# Once we are done annotating the System.map, we no longer need the ranges data. 141*ac7bd094SKris Van Hees# 142*ac7bd094SKris Van HeesFNR == 1 && ARGIND == 3 { 143*ac7bd094SKris Van Hees delete ranges; 144*ac7bd094SKris Van Hees} 145*ac7bd094SKris Van Hees 146*ac7bd094SKris Van Hees# (3) Build a lookup map of built-in module names. 147*ac7bd094SKris Van Hees# 148*ac7bd094SKris Van Hees# Lines from modules.builtin will be like: 149*ac7bd094SKris Van Hees# kernel/crypto/lzo-rle.ko 150*ac7bd094SKris Van Hees# and we record the object name "crypto/lzo-rle". 151*ac7bd094SKris Van Hees# 152*ac7bd094SKris Van HeesARGIND == 3 { 153*ac7bd094SKris Van Hees sub(/kernel\//, ""); # strip off "kernel/" prefix 154*ac7bd094SKris Van Hees sub(/\.ko$/, ""); # strip off .ko suffix 155*ac7bd094SKris Van Hees 156*ac7bd094SKris Van Hees mods[$1] = 1; 157*ac7bd094SKris Van Hees next; 158*ac7bd094SKris Van Hees} 159*ac7bd094SKris Van Hees 160*ac7bd094SKris Van Hees# (4) Get a list of symbols (per object). 161*ac7bd094SKris Van Hees# 162*ac7bd094SKris Van Hees# Symbols by object are read from vmlinux.map, with fallback to vmlinux.o.map 163*ac7bd094SKris Van Hees# if vmlinux is found to have inked in vmlinux.o. 164*ac7bd094SKris Van Hees# 165*ac7bd094SKris Van Hees 166*ac7bd094SKris Van Hees# If we were able to get the data we need from vmlinux.map, there is no need to 167*ac7bd094SKris Van Hees# process vmlinux.o.map. 168*ac7bd094SKris Van Hees# 169*ac7bd094SKris Van HeesFNR == 1 && ARGIND == 5 && total > 0 { 170*ac7bd094SKris Van Hees if (dbg) 171*ac7bd094SKris Van Hees printf "Note: %s is not needed.\n", FILENAME >"/dev/stderr"; 172*ac7bd094SKris Van Hees exit; 173*ac7bd094SKris Van Hees} 174*ac7bd094SKris Van Hees 175*ac7bd094SKris Van Hees# First determine whether we are dealing with a GNU ld or LLVM lld linker map. 176*ac7bd094SKris Van Hees# 177*ac7bd094SKris Van HeesARGIND >= 4 && FNR == 1 && NF == 7 && $1 == "VMA" && $7 == "Symbol" { 178*ac7bd094SKris Van Hees map_is_lld = 1; 179*ac7bd094SKris Van Hees next; 180*ac7bd094SKris Van Hees} 181*ac7bd094SKris Van Hees 182*ac7bd094SKris Van Hees# (LLD) Convert a section record fronm lld format to ld format. 183*ac7bd094SKris Van Hees# 184*ac7bd094SKris Van HeesARGIND >= 4 && map_is_lld && NF == 5 && /[0-9] [^ ]+$/ { 185*ac7bd094SKris Van Hees $0 = $5 " 0x"$1 " 0x"$3 " load address 0x"$2; 186*ac7bd094SKris Van Hees} 187*ac7bd094SKris Van Hees 188*ac7bd094SKris Van Hees# (LLD) Convert an object record from lld format to ld format. 189*ac7bd094SKris Van Hees# 190*ac7bd094SKris Van HeesARGIND >= 4 && map_is_lld && NF == 5 && $5 ~ /:\(/ { 191*ac7bd094SKris Van Hees if (/\.a\(/ && !/ vmlinux\.a\(/) 192*ac7bd094SKris Van Hees next; 193*ac7bd094SKris Van Hees 194*ac7bd094SKris Van Hees gsub(/\)/, ""); 195*ac7bd094SKris Van Hees sub(/:\(/, " "); 196*ac7bd094SKris Van Hees sub(/ vmlinux\.a\(/, " "); 197*ac7bd094SKris Van Hees $0 = " "$6 " 0x"$1 " 0x"$3 " " $5; 198*ac7bd094SKris Van Hees} 199*ac7bd094SKris Van Hees 200*ac7bd094SKris Van Hees# (LLD) Convert a symbol record from lld format to ld format. 201*ac7bd094SKris Van Hees# 202*ac7bd094SKris Van HeesARGIND >= 4 && map_is_lld && NF == 5 && $5 ~ /^[A-Za-z_][A-Za-z0-9_]*$/ { 203*ac7bd094SKris Van Hees $0 = " 0x" $1 " " $5; 204*ac7bd094SKris Van Hees} 205*ac7bd094SKris Van Hees 206*ac7bd094SKris Van Hees# (LLD) We do not need any other ldd linker map records. 207*ac7bd094SKris Van Hees# 208*ac7bd094SKris Van HeesARGIND >= 4 && map_is_lld && /^[0-9a-f]{16} / { 209*ac7bd094SKris Van Hees next; 210*ac7bd094SKris Van Hees} 211*ac7bd094SKris Van Hees 212*ac7bd094SKris Van Hees# Handle section records with long section names (spilling onto a 2nd line). 213*ac7bd094SKris Van Hees# 214*ac7bd094SKris Van HeesARGIND >= 4 && !map_is_lld && NF == 1 && /^[^ ]/ { 215*ac7bd094SKris Van Hees s = $0; 216*ac7bd094SKris Van Hees getline; 217*ac7bd094SKris Van Hees $0 = s " " $0; 218*ac7bd094SKris Van Hees} 219*ac7bd094SKris Van Hees 220*ac7bd094SKris Van Hees# Next section - previous one is done. 221*ac7bd094SKris Van Hees# 222*ac7bd094SKris Van HeesARGIND >= 4 && /^[^ ]/ { 223*ac7bd094SKris Van Hees sect = 0; 224*ac7bd094SKris Van Hees} 225*ac7bd094SKris Van Hees 226*ac7bd094SKris Van Hees# Get the (top level) section name. 227*ac7bd094SKris Van Hees# 228*ac7bd094SKris Van HeesARGIND >= 4 && /^\./ { 229*ac7bd094SKris Van Hees # Explicitly ignore a few sections that are not relevant here. 230*ac7bd094SKris Van Hees if ($1 ~ /^\.orc_/ || $1 ~ /_sites$/ || $1 ~ /\.percpu/) 231*ac7bd094SKris Van Hees next; 232*ac7bd094SKris Van Hees 233*ac7bd094SKris Van Hees # Sections with a 0-address can be ignored as well (in vmlinux.map). 234*ac7bd094SKris Van Hees if (ARGIND == 4 && $2 ~ /^0x0+$/) 235*ac7bd094SKris Van Hees next; 236*ac7bd094SKris Van Hees 237*ac7bd094SKris Van Hees sect = $1; 238*ac7bd094SKris Van Hees 239*ac7bd094SKris Van Hees next; 240*ac7bd094SKris Van Hees} 241*ac7bd094SKris Van Hees 242*ac7bd094SKris Van Hees# If we are not currently in a section we care about, ignore records. 243*ac7bd094SKris Van Hees# 244*ac7bd094SKris Van Hees!sect { 245*ac7bd094SKris Van Hees next; 246*ac7bd094SKris Van Hees} 247*ac7bd094SKris Van Hees 248*ac7bd094SKris Van Hees# Handle object records with long section names (spilling onto a 2nd line). 249*ac7bd094SKris Van Hees# 250*ac7bd094SKris Van HeesARGIND >= 4 && /^ [^ \*]/ && NF == 1 { 251*ac7bd094SKris Van Hees # If the section name is long, the remainder of the entry is found on 252*ac7bd094SKris Van Hees # the next line. 253*ac7bd094SKris Van Hees s = $0; 254*ac7bd094SKris Van Hees getline; 255*ac7bd094SKris Van Hees $0 = s " " $0; 256*ac7bd094SKris Van Hees} 257*ac7bd094SKris Van Hees 258*ac7bd094SKris Van Hees# Objects linked in from static libraries are ignored. 259*ac7bd094SKris Van Hees# If the object is vmlinux.o, we need to consult vmlinux.o.map for per-object 260*ac7bd094SKris Van Hees# symbol information 261*ac7bd094SKris Van Hees# 262*ac7bd094SKris Van HeesARGIND == 4 && /^ [^ ]/ && NF == 4 { 263*ac7bd094SKris Van Hees if ($4 ~ /\.a\(/) 264*ac7bd094SKris Van Hees next; 265*ac7bd094SKris Van Hees 266*ac7bd094SKris Van Hees idx = sect":"$1; 267*ac7bd094SKris Van Hees if (!(idx in sect_addend)) { 268*ac7bd094SKris Van Hees sect_addend[idx] = addr2val($2); 269*ac7bd094SKris Van Hees if (dbg) 270*ac7bd094SKris Van Hees printf "ADDEND %s = %016x\n", idx, sect_addend[idx] >"/dev/stderr"; 271*ac7bd094SKris Van Hees } 272*ac7bd094SKris Van Hees if ($4 == "vmlinux.o") { 273*ac7bd094SKris Van Hees need_o_map = 1; 274*ac7bd094SKris Van Hees next; 275*ac7bd094SKris Van Hees } 276*ac7bd094SKris Van Hees} 277*ac7bd094SKris Van Hees 278*ac7bd094SKris Van Hees# If data from vmlinux.o.map is needed, we only process section and object 279*ac7bd094SKris Van Hees# records from vmlinux.map to determine which section we need to pay attention 280*ac7bd094SKris Van Hees# to in vmlinux.o.map. So skip everything else from vmlinux.map. 281*ac7bd094SKris Van Hees# 282*ac7bd094SKris Van HeesARGIND == 4 && need_o_map { 283*ac7bd094SKris Van Hees next; 284*ac7bd094SKris Van Hees} 285*ac7bd094SKris Van Hees 286*ac7bd094SKris Van Hees# Get module information for the current object. 287*ac7bd094SKris Van Hees# 288*ac7bd094SKris Van HeesARGIND >= 4 && /^ [^ ]/ && NF == 4 { 289*ac7bd094SKris Van Hees msect = $1; 290*ac7bd094SKris Van Hees mod_name = get_module_info($4); 291*ac7bd094SKris Van Hees mod_eaddr = addr2val($2) + addr2val($3); 292*ac7bd094SKris Van Hees 293*ac7bd094SKris Van Hees next; 294*ac7bd094SKris Van Hees} 295*ac7bd094SKris Van Hees 296*ac7bd094SKris Van Hees# Process a symbol record. 297*ac7bd094SKris Van Hees# 298*ac7bd094SKris Van Hees# Evaluate the module information obtained from vmlinux.map (or vmlinux.o.map) 299*ac7bd094SKris Van Hees# as follows: 300*ac7bd094SKris Van Hees# - For all symbols in a given object: 301*ac7bd094SKris Van Hees# - If the symbol is annotated with the same module name(s) that the object 302*ac7bd094SKris Van Hees# belongs to, count it as a match. 303*ac7bd094SKris Van Hees# - Otherwise: 304*ac7bd094SKris Van Hees# - If the symbol is known to have duplicates of which at least one is 305*ac7bd094SKris Van Hees# in a built-in module, disregard it. 306*ac7bd094SKris Van Hees# - If the symbol us not annotated with any module name(s) AND the 307*ac7bd094SKris Van Hees# object belongs to built-in modules, count it as missing. 308*ac7bd094SKris Van Hees# - Otherwise, count it as a mismatch. 309*ac7bd094SKris Van Hees# 310*ac7bd094SKris Van HeesARGIND >= 4 && /^ / && NF == 2 && $1 ~ /^0x/ { 311*ac7bd094SKris Van Hees idx = sect":"msect; 312*ac7bd094SKris Van Hees if (!(idx in sect_addend)) 313*ac7bd094SKris Van Hees next; 314*ac7bd094SKris Van Hees 315*ac7bd094SKris Van Hees addr = addr2val($1); 316*ac7bd094SKris Van Hees 317*ac7bd094SKris Van Hees # Handle the rare but annoying case where a 0-size symbol is placed at 318*ac7bd094SKris Van Hees # the byte *after* the module range. Based on vmlinux.map it will be 319*ac7bd094SKris Van Hees # considered part of the current object, but it falls just beyond the 320*ac7bd094SKris Van Hees # module address range. Unfortunately, its address could be at the 321*ac7bd094SKris Van Hees # start of another built-in module, so the only safe thing to do is to 322*ac7bd094SKris Van Hees # ignore it. 323*ac7bd094SKris Van Hees if (mod_name && addr == mod_eaddr) 324*ac7bd094SKris Van Hees next; 325*ac7bd094SKris Van Hees 326*ac7bd094SKris Van Hees # If we are processing vmlinux.o.map, we need to apply the base address 327*ac7bd094SKris Van Hees # of the section to the relative address on the record. 328*ac7bd094SKris Van Hees # 329*ac7bd094SKris Van Hees if (ARGIND == 5) 330*ac7bd094SKris Van Hees addr += sect_addend[idx]; 331*ac7bd094SKris Van Hees 332*ac7bd094SKris Van Hees idx = addr"-"$2; 333*ac7bd094SKris Van Hees mod = ""; 334*ac7bd094SKris Van Hees if (idx in sym2mod) { 335*ac7bd094SKris Van Hees mod = sym2mod[idx]; 336*ac7bd094SKris Van Hees if (sym2mod[idx] == mod_name) { 337*ac7bd094SKris Van Hees mod_matches++; 338*ac7bd094SKris Van Hees matches++; 339*ac7bd094SKris Van Hees } else if (mod_name == "") { 340*ac7bd094SKris Van Hees print $2 " in " mod " (should NOT be)"; 341*ac7bd094SKris Van Hees mismatches++; 342*ac7bd094SKris Van Hees } else { 343*ac7bd094SKris Van Hees print $2 " in " mod " (should be " mod_name ")"; 344*ac7bd094SKris Van Hees mismatches++; 345*ac7bd094SKris Van Hees } 346*ac7bd094SKris Van Hees } else if (mod_name != "") { 347*ac7bd094SKris Van Hees print $2 " should be in " mod_name; 348*ac7bd094SKris Van Hees missing++; 349*ac7bd094SKris Van Hees } else 350*ac7bd094SKris Van Hees matches++; 351*ac7bd094SKris Van Hees 352*ac7bd094SKris Van Hees total++; 353*ac7bd094SKris Van Hees 354*ac7bd094SKris Van Hees next; 355*ac7bd094SKris Van Hees} 356*ac7bd094SKris Van Hees 357*ac7bd094SKris Van Hees# Issue the comparison report. 358*ac7bd094SKris Van Hees# 359*ac7bd094SKris Van HeesEND { 360*ac7bd094SKris Van Hees if (total) { 361*ac7bd094SKris Van Hees printf "Verification of %s:\n", ARGV[1]; 362*ac7bd094SKris Van Hees printf " Correct matches: %6d (%d%% of total)\n", matches, 100 * matches / total; 363*ac7bd094SKris Van Hees printf " Module matches: %6d (%d%% of matches)\n", mod_matches, 100 * mod_matches / matches; 364*ac7bd094SKris Van Hees printf " Mismatches: %6d (%d%% of total)\n", mismatches, 100 * mismatches / total; 365*ac7bd094SKris Van Hees printf " Missing: %6d (%d%% of total)\n", missing, 100 * missing / total; 366*ac7bd094SKris Van Hees 367*ac7bd094SKris Van Hees if (mismatches || missing) 368*ac7bd094SKris Van Hees exit(1); 369*ac7bd094SKris Van Hees } 370*ac7bd094SKris Van Hees} 371