15f5e7344SKris Van Hees#!/usr/bin/gawk -f 25f5e7344SKris Van Hees# SPDX-License-Identifier: GPL-2.0 35f5e7344SKris Van Hees# generate_builtin_ranges.awk: Generate address range data for builtin modules 45f5e7344SKris Van Hees# Written by Kris Van Hees <[email protected]> 55f5e7344SKris Van Hees# 65f5e7344SKris Van Hees# Usage: generate_builtin_ranges.awk modules.builtin vmlinux.map \ 75f5e7344SKris Van Hees# vmlinux.o.map > modules.builtin.ranges 85f5e7344SKris Van Hees# 95f5e7344SKris Van Hees 105f5e7344SKris Van Hees# Return the module name(s) (if any) associated with the given object. 115f5e7344SKris Van Hees# 125f5e7344SKris Van Hees# If we have seen this object before, return information from the cache. 135f5e7344SKris Van Hees# Otherwise, retrieve it from the corresponding .cmd file. 145f5e7344SKris Van Hees# 155f5e7344SKris Van Heesfunction get_module_info(fn, mod, obj, s) { 165f5e7344SKris Van Hees if (fn in omod) 175f5e7344SKris Van Hees return omod[fn]; 185f5e7344SKris Van Hees 195f5e7344SKris Van Hees if (match(fn, /\/[^/]+$/) == 0) 205f5e7344SKris Van Hees return ""; 215f5e7344SKris Van Hees 225f5e7344SKris Van Hees obj = fn; 235f5e7344SKris Van Hees mod = ""; 245f5e7344SKris Van Hees fn = substr(fn, 1, RSTART) "." substr(fn, RSTART + 1) ".cmd"; 255f5e7344SKris Van Hees if (getline s <fn == 1) { 265f5e7344SKris Van Hees if (match(s, /DKBUILD_MODFILE=['"]+[^'"]+/) > 0) { 275f5e7344SKris Van Hees mod = substr(s, RSTART + 16, RLENGTH - 16); 285f5e7344SKris Van Hees gsub(/['"]/, "", mod); 295f5e7344SKris Van Hees } else if (match(s, /RUST_MODFILE=[^ ]+/) > 0) 305f5e7344SKris Van Hees mod = substr(s, RSTART + 13, RLENGTH - 13); 315f5e7344SKris Van Hees } 325f5e7344SKris Van Hees close(fn); 335f5e7344SKris Van Hees 345f5e7344SKris Van Hees # A single module (common case) also reflects objects that are not part 355f5e7344SKris Van Hees # of a module. Some of those objects have names that are also a module 365f5e7344SKris Van Hees # name (e.g. core). We check the associated module file name, and if 375f5e7344SKris Van Hees # they do not match, the object is not part of a module. 385f5e7344SKris Van Hees if (mod !~ / /) { 395f5e7344SKris Van Hees if (!(mod in mods)) 405f5e7344SKris Van Hees mod = ""; 415f5e7344SKris Van Hees } 425f5e7344SKris Van Hees 435f5e7344SKris Van Hees gsub(/([^/ ]*\/)+/, "", mod); 445f5e7344SKris Van Hees gsub(/-/, "_", mod); 455f5e7344SKris Van Hees 465f5e7344SKris Van Hees # At this point, mod is a single (valid) module name, or a list of 475f5e7344SKris Van Hees # module names (that do not need validation). 485f5e7344SKris Van Hees omod[obj] = mod; 495f5e7344SKris Van Hees 505f5e7344SKris Van Hees return mod; 515f5e7344SKris Van Hees} 525f5e7344SKris Van Hees 535f5e7344SKris Van Hees# Update the ranges entry for the given module 'mod' in section 'osect'. 545f5e7344SKris Van Hees# 555f5e7344SKris Van Hees# We use a modified absolute start address (soff + base) as index because we 565f5e7344SKris Van Hees# may need to insert an anchor record later that must be at the start of the 575f5e7344SKris Van Hees# section data, and the first module may very well start at the same address. 585f5e7344SKris Van Hees# So, we use (addr << 1) + 1 to allow a possible anchor record to be placed at 595f5e7344SKris Van Hees# (addr << 1). This is safe because the index is only used to sort the entries 605f5e7344SKris Van Hees# before writing them out. 615f5e7344SKris Van Hees# 625f5e7344SKris Van Heesfunction update_entry(osect, mod, soff, eoff, sect, idx) { 635f5e7344SKris Van Hees sect = sect_in[osect]; 645f5e7344SKris Van Hees idx = sprintf("%016x", (soff + sect_base[osect]) * 2 + 1); 655f5e7344SKris Van Hees entries[idx] = sprintf("%s %08x-%08x %s", sect, soff, eoff, mod); 665f5e7344SKris Van Hees count[sect]++; 675f5e7344SKris Van Hees} 685f5e7344SKris Van Hees 695f5e7344SKris Van Hees# (1) Build a lookup map of built-in module names. 705f5e7344SKris Van Hees# 715f5e7344SKris Van Hees# The first file argument is used as input (modules.builtin). 725f5e7344SKris Van Hees# 735f5e7344SKris Van Hees# Lines will be like: 745f5e7344SKris Van Hees# kernel/crypto/lzo-rle.ko 755f5e7344SKris Van Hees# and we record the object name "crypto/lzo-rle". 765f5e7344SKris Van Hees# 775f5e7344SKris Van HeesARGIND == 1 { 785f5e7344SKris Van Hees sub(/kernel\//, ""); # strip off "kernel/" prefix 795f5e7344SKris Van Hees sub(/\.ko$/, ""); # strip off .ko suffix 805f5e7344SKris Van Hees 815f5e7344SKris Van Hees mods[$1] = 1; 825f5e7344SKris Van Hees next; 835f5e7344SKris Van Hees} 845f5e7344SKris Van Hees 855f5e7344SKris Van Hees# (2) Collect address information for each section. 865f5e7344SKris Van Hees# 875f5e7344SKris Van Hees# The second file argument is used as input (vmlinux.map). 885f5e7344SKris Van Hees# 895f5e7344SKris Van Hees# We collect the base address of the section in order to convert all addresses 905f5e7344SKris Van Hees# in the section into offset values. 915f5e7344SKris Van Hees# 925f5e7344SKris Van Hees# We collect the address of the anchor (or first symbol in the section if there 935f5e7344SKris Van Hees# is no explicit anchor) to allow users of the range data to calculate address 945f5e7344SKris Van Hees# ranges based on the actual load address of the section in the running kernel. 955f5e7344SKris Van Hees# 965f5e7344SKris Van Hees# We collect the start address of any sub-section (section included in the top 975f5e7344SKris Van Hees# level section being processed). This is needed when the final linking was 985f5e7344SKris Van Hees# done using vmlinux.a because then the list of objects contained in each 995f5e7344SKris Van Hees# section is to be obtained from vmlinux.o.map. The offset of the sub-section 1005f5e7344SKris Van Hees# is recorded here, to be used as an addend when processing vmlinux.o.map 1015f5e7344SKris Van Hees# later. 1025f5e7344SKris Van Hees# 1035f5e7344SKris Van Hees 1045f5e7344SKris Van Hees# Both GNU ld and LLVM lld linker map format are supported by converting LLVM 1055f5e7344SKris Van Hees# lld linker map records into equivalent GNU ld linker map records. 1065f5e7344SKris Van Hees# 1075f5e7344SKris Van Hees# The first record of the vmlinux.map file provides enough information to know 1085f5e7344SKris Van Hees# which format we are dealing with. 1095f5e7344SKris Van Hees# 1105f5e7344SKris Van HeesARGIND == 2 && FNR == 1 && NF == 7 && $1 == "VMA" && $7 == "Symbol" { 1115f5e7344SKris Van Hees map_is_lld = 1; 1125f5e7344SKris Van Hees if (dbg) 1135f5e7344SKris Van Hees printf "NOTE: %s uses LLVM lld linker map format\n", FILENAME >"/dev/stderr"; 1145f5e7344SKris Van Hees next; 1155f5e7344SKris Van Hees} 1165f5e7344SKris Van Hees 1175f5e7344SKris Van Hees# (LLD) Convert a section record fronm lld format to ld format. 1185f5e7344SKris Van Hees# 1195f5e7344SKris Van Hees# lld: ffffffff82c00000 2c00000 2493c0 8192 .data 1205f5e7344SKris Van Hees# -> 1215f5e7344SKris Van Hees# ld: .data 0xffffffff82c00000 0x2493c0 load address 0x0000000002c00000 1225f5e7344SKris Van Hees# 1235f5e7344SKris Van HeesARGIND == 2 && map_is_lld && NF == 5 && /[0-9] [^ ]+$/ { 1245f5e7344SKris Van Hees $0 = $5 " 0x"$1 " 0x"$3 " load address 0x"$2; 1255f5e7344SKris Van Hees} 1265f5e7344SKris Van Hees 1275f5e7344SKris Van Hees# (LLD) Convert an anchor record from lld format to ld format. 1285f5e7344SKris Van Hees# 1295f5e7344SKris Van Hees# lld: ffffffff81000000 1000000 0 1 _text = . 1305f5e7344SKris Van Hees# -> 1315f5e7344SKris Van Hees# ld: 0xffffffff81000000 _text = . 1325f5e7344SKris Van Hees# 1335f5e7344SKris Van HeesARGIND == 2 && map_is_lld && !anchor && NF == 7 && raw_addr == "0x"$1 && $6 == "=" && $7 == "." { 1345f5e7344SKris Van Hees $0 = " 0x"$1 " " $5 " = ."; 1355f5e7344SKris Van Hees} 1365f5e7344SKris Van Hees 1375f5e7344SKris Van Hees# (LLD) Convert an object record from lld format to ld format. 1385f5e7344SKris Van Hees# 1395f5e7344SKris Van Hees# lld: 11480 11480 1f07 16 vmlinux.a(arch/x86/events/amd/uncore.o):(.text) 1405f5e7344SKris Van Hees# -> 1415f5e7344SKris Van Hees# ld: .text 0x0000000000011480 0x1f07 arch/x86/events/amd/uncore.o 1425f5e7344SKris Van Hees# 1435f5e7344SKris Van HeesARGIND == 2 && map_is_lld && NF == 5 && $5 ~ /:\(/ { 1445f5e7344SKris Van Hees gsub(/\)/, ""); 1455f5e7344SKris Van Hees sub(/ vmlinux\.a\(/, " "); 1465f5e7344SKris Van Hees sub(/:\(/, " "); 1475f5e7344SKris Van Hees $0 = " "$6 " 0x"$1 " 0x"$3 " " $5; 1485f5e7344SKris Van Hees} 1495f5e7344SKris Van Hees 1505f5e7344SKris Van Hees# (LLD) Convert a symbol record from lld format to ld format. 1515f5e7344SKris Van Hees# 1525f5e7344SKris Van Hees# We only care about these while processing a section for which no anchor has 1535f5e7344SKris Van Hees# been determined yet. 1545f5e7344SKris Van Hees# 1555f5e7344SKris Van Hees# lld: ffffffff82a859a4 2a859a4 0 1 btf_ksym_iter_id 1565f5e7344SKris Van Hees# -> 1575f5e7344SKris Van Hees# ld: 0xffffffff82a859a4 btf_ksym_iter_id 1585f5e7344SKris Van Hees# 1595f5e7344SKris Van HeesARGIND == 2 && map_is_lld && sect && !anchor && NF == 5 && $5 ~ /^[_A-Za-z][_A-Za-z0-9]*$/ { 1605f5e7344SKris Van Hees $0 = " 0x"$1 " " $5; 1615f5e7344SKris Van Hees} 1625f5e7344SKris Van Hees 1635f5e7344SKris Van Hees# (LLD) We do not need any other ldd linker map records. 1645f5e7344SKris Van Hees# 1655f5e7344SKris Van HeesARGIND == 2 && map_is_lld && /^[0-9a-f]{16} / { 1665f5e7344SKris Van Hees next; 1675f5e7344SKris Van Hees} 1685f5e7344SKris Van Hees 1695f5e7344SKris Van Hees# (LD) Section records with just the section name at the start of the line 1705f5e7344SKris Van Hees# need to have the next line pulled in to determine whether it is a 1715f5e7344SKris Van Hees# loadable section. If it is, the next line will contains a hex value 1725f5e7344SKris Van Hees# as first and second items. 1735f5e7344SKris Van Hees# 1745f5e7344SKris Van HeesARGIND == 2 && !map_is_lld && NF == 1 && /^[^ ]/ { 1755f5e7344SKris Van Hees s = $0; 1765f5e7344SKris Van Hees getline; 1775f5e7344SKris Van Hees if ($1 !~ /^0x/ || $2 !~ /^0x/) 1785f5e7344SKris Van Hees next; 1795f5e7344SKris Van Hees 1805f5e7344SKris Van Hees $0 = s " " $0; 1815f5e7344SKris Van Hees} 1825f5e7344SKris Van Hees 1835f5e7344SKris Van Hees# (LD) Object records with just the section name denote records with a long 1845f5e7344SKris Van Hees# section name for which the remainder of the record can be found on the 1855f5e7344SKris Van Hees# next line. 1865f5e7344SKris Van Hees# 1875f5e7344SKris Van Hees# (This is also needed for vmlinux.o.map, when used.) 1885f5e7344SKris Van Hees# 1895f5e7344SKris Van HeesARGIND >= 2 && !map_is_lld && NF == 1 && /^ [^ \*]/ { 1905f5e7344SKris Van Hees s = $0; 1915f5e7344SKris Van Hees getline; 1925f5e7344SKris Van Hees $0 = s " " $0; 1935f5e7344SKris Van Hees} 1945f5e7344SKris Van Hees 1955f5e7344SKris Van Hees# Beginning a new section - done with the previous one (if any). 1965f5e7344SKris Van Hees# 1975f5e7344SKris Van HeesARGIND == 2 && /^[^ ]/ { 1985f5e7344SKris Van Hees sect = 0; 1995f5e7344SKris Van Hees} 2005f5e7344SKris Van Hees 2015f5e7344SKris Van Hees# Process a loadable section (we only care about .-sections). 2025f5e7344SKris Van Hees# 2035f5e7344SKris Van Hees# Record the section name and its base address. 2045f5e7344SKris Van Hees# We also record the raw (non-stripped) address of the section because it can 2055f5e7344SKris Van Hees# be used to identify an anchor record. 2065f5e7344SKris Van Hees# 2075f5e7344SKris Van Hees# Note: 2085f5e7344SKris Van Hees# Since some AWK implementations cannot handle large integers, we strip off the 2095f5e7344SKris Van Hees# first 4 hex digits from the address. This is safe because the kernel space 2105f5e7344SKris Van Hees# is not large enough for addresses to extend into those digits. The portion 2115f5e7344SKris Van Hees# to strip off is stored in addr_prefix as a regexp, so further clauses can 2125f5e7344SKris Van Hees# perform a simple substitution to do the address stripping. 2135f5e7344SKris Van Hees# 2145f5e7344SKris Van HeesARGIND == 2 && /^\./ { 2155f5e7344SKris Van Hees # Explicitly ignore a few sections that are not relevant here. 2165f5e7344SKris Van Hees if ($1 ~ /^\.orc_/ || $1 ~ /_sites$/ || $1 ~ /\.percpu/) 2175f5e7344SKris Van Hees next; 2185f5e7344SKris Van Hees 2195f5e7344SKris Van Hees # Sections with a 0-address can be ignored as well. 2205f5e7344SKris Van Hees if ($2 ~ /^0x0+$/) 2215f5e7344SKris Van Hees next; 2225f5e7344SKris Van Hees 2235f5e7344SKris Van Hees raw_addr = $2; 2245f5e7344SKris Van Hees addr_prefix = "^" substr($2, 1, 6); 2255f5e7344SKris Van Hees base = $2; 2265f5e7344SKris Van Hees sub(addr_prefix, "0x", base); 2275f5e7344SKris Van Hees base = strtonum(base); 2285f5e7344SKris Van Hees sect = $1; 2295f5e7344SKris Van Hees anchor = 0; 2305f5e7344SKris Van Hees sect_base[sect] = base; 2315f5e7344SKris Van Hees sect_size[sect] = strtonum($3); 2325f5e7344SKris Van Hees 2335f5e7344SKris Van Hees if (dbg) 2345f5e7344SKris Van Hees printf "[%s] BASE %016x\n", sect, base >"/dev/stderr"; 2355f5e7344SKris Van Hees 2365f5e7344SKris Van Hees next; 2375f5e7344SKris Van Hees} 2385f5e7344SKris Van Hees 2395f5e7344SKris Van Hees# If we are not in a section we care about, we ignore the record. 2405f5e7344SKris Van Hees# 2415f5e7344SKris Van HeesARGIND == 2 && !sect { 2425f5e7344SKris Van Hees next; 2435f5e7344SKris Van Hees} 2445f5e7344SKris Van Hees 2455f5e7344SKris Van Hees# Record the first anchor symbol for the current section. 2465f5e7344SKris Van Hees# 2475f5e7344SKris Van Hees# An anchor record for the section bears the same raw address as the section 2485f5e7344SKris Van Hees# record. 2495f5e7344SKris Van Hees# 2505f5e7344SKris Van HeesARGIND == 2 && !anchor && NF == 4 && raw_addr == $1 && $3 == "=" && $4 == "." { 2515f5e7344SKris Van Hees anchor = sprintf("%s %08x-%08x = %s", sect, 0, 0, $2); 2525f5e7344SKris Van Hees sect_anchor[sect] = anchor; 2535f5e7344SKris Van Hees 2545f5e7344SKris Van Hees if (dbg) 2555f5e7344SKris Van Hees printf "[%s] ANCHOR %016x = %s (.)\n", sect, 0, $2 >"/dev/stderr"; 2565f5e7344SKris Van Hees 2575f5e7344SKris Van Hees next; 2585f5e7344SKris Van Hees} 2595f5e7344SKris Van Hees 2605f5e7344SKris Van Hees# If no anchor record was found for the current section, use the first symbol 2615f5e7344SKris Van Hees# in the section as anchor. 2625f5e7344SKris Van Hees# 2635f5e7344SKris Van HeesARGIND == 2 && !anchor && NF == 2 && $1 ~ /^0x/ && $2 !~ /^0x/ { 2645f5e7344SKris Van Hees addr = $1; 2655f5e7344SKris Van Hees sub(addr_prefix, "0x", addr); 2665f5e7344SKris Van Hees addr = strtonum(addr) - base; 2675f5e7344SKris Van Hees anchor = sprintf("%s %08x-%08x = %s", sect, addr, addr, $2); 2685f5e7344SKris Van Hees sect_anchor[sect] = anchor; 2695f5e7344SKris Van Hees 2705f5e7344SKris Van Hees if (dbg) 2715f5e7344SKris Van Hees printf "[%s] ANCHOR %016x = %s\n", sect, addr, $2 >"/dev/stderr"; 2725f5e7344SKris Van Hees 2735f5e7344SKris Van Hees next; 2745f5e7344SKris Van Hees} 2755f5e7344SKris Van Hees 2765f5e7344SKris Van Hees# The first occurrence of a section name in an object record establishes the 2775f5e7344SKris Van Hees# addend (often 0) for that section. This information is needed to handle 2785f5e7344SKris Van Hees# sections that get combined in the final linking of vmlinux (e.g. .head.text 2795f5e7344SKris Van Hees# getting included at the start of .text). 2805f5e7344SKris Van Hees# 2815f5e7344SKris Van Hees# If the section does not have a base yet, use the base of the encapsulating 2825f5e7344SKris Van Hees# section. 2835f5e7344SKris Van Hees# 2845f5e7344SKris Van HeesARGIND == 2 && sect && NF == 4 && /^ [^ \*]/ && !($1 in sect_addend) { 285*87bb368dSKris Van Hees # There are a few sections with constant data (without symbols) that 286*87bb368dSKris Van Hees # can get resized during linking, so it is best to ignore them. 287*87bb368dSKris Van Hees if ($1 ~ /^\.rodata\.(cst|str)[0-9]/) 288*87bb368dSKris Van Hees next; 289*87bb368dSKris Van Hees 2905f5e7344SKris Van Hees if (!($1 in sect_base)) { 2915f5e7344SKris Van Hees sect_base[$1] = base; 2925f5e7344SKris Van Hees 2935f5e7344SKris Van Hees if (dbg) 2945f5e7344SKris Van Hees printf "[%s] BASE %016x\n", $1, base >"/dev/stderr"; 2955f5e7344SKris Van Hees } 2965f5e7344SKris Van Hees 2975f5e7344SKris Van Hees addr = $2; 2985f5e7344SKris Van Hees sub(addr_prefix, "0x", addr); 2995f5e7344SKris Van Hees addr = strtonum(addr); 3005f5e7344SKris Van Hees sect_addend[$1] = addr - sect_base[$1]; 3015f5e7344SKris Van Hees sect_in[$1] = sect; 3025f5e7344SKris Van Hees 3035f5e7344SKris Van Hees if (dbg) 3045f5e7344SKris Van Hees printf "[%s] ADDEND %016x - %016x = %016x\n", $1, addr, base, sect_addend[$1] >"/dev/stderr"; 3055f5e7344SKris Van Hees 3065f5e7344SKris Van Hees # If the object is vmlinux.o then we will need vmlinux.o.map to get the 3075f5e7344SKris Van Hees # actual offsets of objects. 3085f5e7344SKris Van Hees if ($4 == "vmlinux.o") 3095f5e7344SKris Van Hees need_o_map = 1; 3105f5e7344SKris Van Hees} 3115f5e7344SKris Van Hees 3125f5e7344SKris Van Hees# (3) Collect offset ranges (relative to the section base address) for built-in 3135f5e7344SKris Van Hees# modules. 3145f5e7344SKris Van Hees# 3155f5e7344SKris Van Hees# If the final link was done using the actual objects, vmlinux.map contains all 3165f5e7344SKris Van Hees# the information we need (see section (3a)). 3175f5e7344SKris Van Hees# If linking was done using vmlinux.a as intermediary, we will need to process 3185f5e7344SKris Van Hees# vmlinux.o.map (see section (3b)). 3195f5e7344SKris Van Hees 3205f5e7344SKris Van Hees# (3a) Determine offset range info using vmlinux.map. 3215f5e7344SKris Van Hees# 3225f5e7344SKris Van Hees# Since we are already processing vmlinux.map, the top level section that is 3235f5e7344SKris Van Hees# being processed is already known. If we do not have a base address for it, 3245f5e7344SKris Van Hees# we do not need to process records for it. 3255f5e7344SKris Van Hees# 3265f5e7344SKris Van Hees# Given the object name, we determine the module(s) (if any) that the current 3275f5e7344SKris Van Hees# object is associated with. 3285f5e7344SKris Van Hees# 3295f5e7344SKris Van Hees# If we were already processing objects for a (list of) module(s): 3305f5e7344SKris Van Hees# - If the current object belongs to the same module(s), update the range data 3315f5e7344SKris Van Hees# to include the current object. 3325f5e7344SKris Van Hees# - Otherwise, ensure that the end offset of the range is valid. 3335f5e7344SKris Van Hees# 3345f5e7344SKris Van Hees# If the current object does not belong to a built-in module, ignore it. 3355f5e7344SKris Van Hees# 3365f5e7344SKris Van Hees# If it does, we add a new built-in module offset range record. 3375f5e7344SKris Van Hees# 3385f5e7344SKris Van HeesARGIND == 2 && !need_o_map && /^ [^ ]/ && NF == 4 && $3 != "0x0" { 3395f5e7344SKris Van Hees if (!(sect in sect_base)) 3405f5e7344SKris Van Hees next; 3415f5e7344SKris Van Hees 3425f5e7344SKris Van Hees # Turn the address into an offset from the section base. 3435f5e7344SKris Van Hees soff = $2; 3445f5e7344SKris Van Hees sub(addr_prefix, "0x", soff); 3455f5e7344SKris Van Hees soff = strtonum(soff) - sect_base[sect]; 3465f5e7344SKris Van Hees eoff = soff + strtonum($3); 3475f5e7344SKris Van Hees 3485f5e7344SKris Van Hees # Determine which (if any) built-in modules the object belongs to. 3495f5e7344SKris Van Hees mod = get_module_info($4); 3505f5e7344SKris Van Hees 3515f5e7344SKris Van Hees # If we are processing a built-in module: 3525f5e7344SKris Van Hees # - If the current object is within the same module, we update its 3535f5e7344SKris Van Hees # entry by extending the range and move on 3545f5e7344SKris Van Hees # - Otherwise: 3555f5e7344SKris Van Hees # + If we are still processing within the same main section, we 3565f5e7344SKris Van Hees # validate the end offset against the start offset of the 3575f5e7344SKris Van Hees # current object (e.g. .rodata.str1.[18] objects are often 3585f5e7344SKris Van Hees # listed with an incorrect size in the linker map) 3595f5e7344SKris Van Hees # + Otherwise, we validate the end offset against the section 3605f5e7344SKris Van Hees # size 3615f5e7344SKris Van Hees if (mod_name) { 3625f5e7344SKris Van Hees if (mod == mod_name) { 3635f5e7344SKris Van Hees mod_eoff = eoff; 3645f5e7344SKris Van Hees update_entry(mod_sect, mod_name, mod_soff, eoff); 3655f5e7344SKris Van Hees 3665f5e7344SKris Van Hees next; 3675f5e7344SKris Van Hees } else if (sect == sect_in[mod_sect]) { 3685f5e7344SKris Van Hees if (mod_eoff > soff) 3695f5e7344SKris Van Hees update_entry(mod_sect, mod_name, mod_soff, soff); 3705f5e7344SKris Van Hees } else { 3715f5e7344SKris Van Hees v = sect_size[sect_in[mod_sect]]; 3725f5e7344SKris Van Hees if (mod_eoff > v) 3735f5e7344SKris Van Hees update_entry(mod_sect, mod_name, mod_soff, v); 3745f5e7344SKris Van Hees } 3755f5e7344SKris Van Hees } 3765f5e7344SKris Van Hees 3775f5e7344SKris Van Hees mod_name = mod; 3785f5e7344SKris Van Hees 3795f5e7344SKris Van Hees # If we encountered an object that is not part of a built-in module, we 3805f5e7344SKris Van Hees # do not need to record any data. 3815f5e7344SKris Van Hees if (!mod) 3825f5e7344SKris Van Hees next; 3835f5e7344SKris Van Hees 3845f5e7344SKris Van Hees # At this point, we encountered the start of a new built-in module. 3855f5e7344SKris Van Hees mod_name = mod; 3865f5e7344SKris Van Hees mod_soff = soff; 3875f5e7344SKris Van Hees mod_eoff = eoff; 3885f5e7344SKris Van Hees mod_sect = $1; 3895f5e7344SKris Van Hees update_entry($1, mod, soff, mod_eoff); 3905f5e7344SKris Van Hees 3915f5e7344SKris Van Hees next; 3925f5e7344SKris Van Hees} 3935f5e7344SKris Van Hees 3945f5e7344SKris Van Hees# If we do not need to parse the vmlinux.o.map file, we are done. 3955f5e7344SKris Van Hees# 3965f5e7344SKris Van HeesARGIND == 3 && !need_o_map { 3975f5e7344SKris Van Hees if (dbg) 3985f5e7344SKris Van Hees printf "Note: %s is not needed.\n", FILENAME >"/dev/stderr"; 3995f5e7344SKris Van Hees exit; 4005f5e7344SKris Van Hees} 4015f5e7344SKris Van Hees 4025f5e7344SKris Van Hees# (3) Collect offset ranges (relative to the section base address) for built-in 4035f5e7344SKris Van Hees# modules. 4045f5e7344SKris Van Hees# 4055f5e7344SKris Van Hees 4065f5e7344SKris Van Hees# (LLD) Convert an object record from lld format to ld format. 4075f5e7344SKris Van Hees# 4085f5e7344SKris Van HeesARGIND == 3 && map_is_lld && NF == 5 && $5 ~ /:\(/ { 4095f5e7344SKris Van Hees gsub(/\)/, ""); 4105f5e7344SKris Van Hees sub(/:\(/, " "); 4115f5e7344SKris Van Hees 4125f5e7344SKris Van Hees sect = $6; 4135f5e7344SKris Van Hees if (!(sect in sect_addend)) 4145f5e7344SKris Van Hees next; 4155f5e7344SKris Van Hees 4165f5e7344SKris Van Hees sub(/ vmlinux\.a\(/, " "); 4175f5e7344SKris Van Hees $0 = " "sect " 0x"$1 " 0x"$3 " " $5; 4185f5e7344SKris Van Hees} 4195f5e7344SKris Van Hees 4205f5e7344SKris Van Hees# (3b) Determine offset range info using vmlinux.o.map. 4215f5e7344SKris Van Hees# 4225f5e7344SKris Van Hees# If we do not know an addend for the object's section, we are interested in 4235f5e7344SKris Van Hees# anything within that section. 4245f5e7344SKris Van Hees# 4255f5e7344SKris Van Hees# Determine the top-level section that the object's section was included in 4265f5e7344SKris Van Hees# during the final link. This is the section name offset range data will be 4275f5e7344SKris Van Hees# associated with for this object. 4285f5e7344SKris Van Hees# 4295f5e7344SKris Van Hees# The remainder of the processing of the current object record follows the 4305f5e7344SKris Van Hees# procedure outlined in (3a). 4315f5e7344SKris Van Hees# 4325f5e7344SKris Van HeesARGIND == 3 && /^ [^ ]/ && NF == 4 && $3 != "0x0" { 4335f5e7344SKris Van Hees osect = $1; 4345f5e7344SKris Van Hees if (!(osect in sect_addend)) 4355f5e7344SKris Van Hees next; 4365f5e7344SKris Van Hees 4375f5e7344SKris Van Hees # We need to work with the main section. 4385f5e7344SKris Van Hees sect = sect_in[osect]; 4395f5e7344SKris Van Hees 4405f5e7344SKris Van Hees # Turn the address into an offset from the section base. 4415f5e7344SKris Van Hees soff = $2; 4425f5e7344SKris Van Hees sub(addr_prefix, "0x", soff); 4435f5e7344SKris Van Hees soff = strtonum(soff) + sect_addend[osect]; 4445f5e7344SKris Van Hees eoff = soff + strtonum($3); 4455f5e7344SKris Van Hees 4465f5e7344SKris Van Hees # Determine which (if any) built-in modules the object belongs to. 4475f5e7344SKris Van Hees mod = get_module_info($4); 4485f5e7344SKris Van Hees 4495f5e7344SKris Van Hees # If we are processing a built-in module: 4505f5e7344SKris Van Hees # - If the current object is within the same module, we update its 4515f5e7344SKris Van Hees # entry by extending the range and move on 4525f5e7344SKris Van Hees # - Otherwise: 4535f5e7344SKris Van Hees # + If we are still processing within the same main section, we 4545f5e7344SKris Van Hees # validate the end offset against the start offset of the 4555f5e7344SKris Van Hees # current object (e.g. .rodata.str1.[18] objects are often 4565f5e7344SKris Van Hees # listed with an incorrect size in the linker map) 4575f5e7344SKris Van Hees # + Otherwise, we validate the end offset against the section 4585f5e7344SKris Van Hees # size 4595f5e7344SKris Van Hees if (mod_name) { 4605f5e7344SKris Van Hees if (mod == mod_name) { 4615f5e7344SKris Van Hees mod_eoff = eoff; 4625f5e7344SKris Van Hees update_entry(mod_sect, mod_name, mod_soff, eoff); 4635f5e7344SKris Van Hees 4645f5e7344SKris Van Hees next; 4655f5e7344SKris Van Hees } else if (sect == sect_in[mod_sect]) { 4665f5e7344SKris Van Hees if (mod_eoff > soff) 4675f5e7344SKris Van Hees update_entry(mod_sect, mod_name, mod_soff, soff); 4685f5e7344SKris Van Hees } else { 4695f5e7344SKris Van Hees v = sect_size[sect_in[mod_sect]]; 4705f5e7344SKris Van Hees if (mod_eoff > v) 4715f5e7344SKris Van Hees update_entry(mod_sect, mod_name, mod_soff, v); 4725f5e7344SKris Van Hees } 4735f5e7344SKris Van Hees } 4745f5e7344SKris Van Hees 4755f5e7344SKris Van Hees mod_name = mod; 4765f5e7344SKris Van Hees 4775f5e7344SKris Van Hees # If we encountered an object that is not part of a built-in module, we 4785f5e7344SKris Van Hees # do not need to record any data. 4795f5e7344SKris Van Hees if (!mod) 4805f5e7344SKris Van Hees next; 4815f5e7344SKris Van Hees 4825f5e7344SKris Van Hees # At this point, we encountered the start of a new built-in module. 4835f5e7344SKris Van Hees mod_name = mod; 4845f5e7344SKris Van Hees mod_soff = soff; 4855f5e7344SKris Van Hees mod_eoff = eoff; 4865f5e7344SKris Van Hees mod_sect = osect; 4875f5e7344SKris Van Hees update_entry(osect, mod, soff, mod_eoff); 4885f5e7344SKris Van Hees 4895f5e7344SKris Van Hees next; 4905f5e7344SKris Van Hees} 4915f5e7344SKris Van Hees 4925f5e7344SKris Van Hees# (4) Generate the output. 4935f5e7344SKris Van Hees# 4945f5e7344SKris Van Hees# Anchor records are added for each section that contains offset range data 4955f5e7344SKris Van Hees# records. They are added at an adjusted section base address (base << 1) to 4965f5e7344SKris Van Hees# ensure they come first in the second records (see update_entry() above for 4975f5e7344SKris Van Hees# more information). 4985f5e7344SKris Van Hees# 4995f5e7344SKris Van Hees# All entries are sorted by (adjusted) address to ensure that the output can be 5005f5e7344SKris Van Hees# parsed in strict ascending address order. 5015f5e7344SKris Van Hees# 5025f5e7344SKris Van HeesEND { 5035f5e7344SKris Van Hees for (sect in count) { 5045f5e7344SKris Van Hees if (sect in sect_anchor) { 5055f5e7344SKris Van Hees idx = sprintf("%016x", sect_base[sect] * 2); 5065f5e7344SKris Van Hees entries[idx] = sect_anchor[sect]; 5075f5e7344SKris Van Hees } 5085f5e7344SKris Van Hees } 5095f5e7344SKris Van Hees 5105f5e7344SKris Van Hees n = asorti(entries, indices); 5115f5e7344SKris Van Hees for (i = 1; i <= n; i++) 5125f5e7344SKris Van Hees print entries[indices[i]]; 5135f5e7344SKris Van Hees} 514