Nexoniarz is the sole author and SchOS was never published under Apache-2.0, so this is a straight relicence. LICENSE is the FSF GPLv2 text, every first-party SPDX header moves to GPL-2.0-or-later, and NOTICE, README.md, docs/licensing.md and the site say so. projects/schfs-linux follows the rest of the tree. The GPL gives copyleft: a fork has to ship its source. It also lifts the old "Linux drivers, never" rule, since GPL-2.0-only code combines with GPL-2.0-or-later. "Or later" leaves room for GPLv3, but one binary still has to pick one version, so docs/licensing.md now keeps Apache-2.0 and GPLv3 code out of the kernel to keep Linux code possible there. BSD 4-clause code goes from "avoid" to "no", because the advertising clause is GPL-incompatible. LDLS still ships no .ko. That boundary is now project policy rather than a legal requirement, and ldls.md, devices.md and licensing.md section 6 say so. refmod declares license=GPL, and ldls-check passes (27 checks). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
145 lines
4.8 KiB
Perl
145 lines
4.8 KiB
Perl
#!/usr/bin/perl
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
#
|
|
# Turn `nm -n kernel` into a symbol table the kernel can carry with it.
|
|
#
|
|
# docs/architecture/debugging.md milestone D0. Everything the debugger prints is an
|
|
# address until this exists, and an address has to be resolved by hand against
|
|
# a disassembly that may not be the one that was running.
|
|
#
|
|
# Perl and not Python, deliberately: this runs on every kernel link, so it is
|
|
# on the critical path of a clean build, and tools/vectors.pl already makes
|
|
# perl a requirement there. The Makefile comment above include/logo.h says why
|
|
# that line is worth holding.
|
|
#
|
|
# Two modes:
|
|
# (default) read nm output on stdin, write a C file on stdout
|
|
# --list read nm output on stdin, write "addr name" lines -- used by the
|
|
# Makefile to prove the two link passes agree
|
|
#
|
|
# The layout trick this depends on: .ksym is placed after .text and .rodata in
|
|
# kernel/kernel.ld, so adding the table to the image cannot move any of the
|
|
# text symbols that are *in* the table. Two passes, and the second is stable.
|
|
# The Makefile verifies that rather than trusting it.
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
# hex() on a 64-bit kernel address is fine on any perl with 64-bit integers,
|
|
# which is every perl this will meet; the warning is about 32-bit ones.
|
|
no warnings q(portable);
|
|
|
|
my $list = (@ARGV && $ARGV[0] eq '--list');
|
|
|
|
my @sym; # [addr, name]
|
|
my $textend = 0;
|
|
|
|
while (my $line = <STDIN>) {
|
|
chomp $line;
|
|
# "ffff800000100000 T begin". Symbols with no address print as spaces and
|
|
# fall out here on the field count.
|
|
my ($addr, $type, $name) = $line =~ /^([0-9a-fA-F]+)\s+(\S)\s+(\S+)$/
|
|
or next;
|
|
|
|
# etext is the end of the text section, and it is the only non-function we
|
|
# want: without it a lookup of an address past the last function walks off
|
|
# the end of the table and names whatever was linked last.
|
|
if ($name eq 'etext') {
|
|
$textend = hex($addr);
|
|
next;
|
|
}
|
|
|
|
# t/T are text, w/W are weak text. Everything else is data, bss or absolute
|
|
# and naming it would make a code address resolve to a variable.
|
|
next unless $type =~ /^[tTwW]$/;
|
|
|
|
# Compiler-local labels. They have no meaning outside one translation unit
|
|
# and they would shadow the function they sit inside.
|
|
next if $name =~ /^\.L/;
|
|
next if $name =~ /\$/;
|
|
|
|
push @sym, [hex($addr), $name, $type];
|
|
}
|
|
|
|
die "ksyms: no text symbols on stdin\n" unless @sym;
|
|
|
|
# nm -n sorts numerically, but ties come out in whatever order the symbol table
|
|
# had them. Prefer the global at a shared address: `begin` and `mboot_header`
|
|
# are the same byte, and naming that byte `begin` tells you nothing.
|
|
my @uniq;
|
|
for my $s (@sym) {
|
|
if (@uniq && $uniq[-1][0] == $s->[0]) {
|
|
$uniq[-1] = $s if $s->[2] =~ /^[TW]$/ && $uniq[-1][2] =~ /^[tw]$/;
|
|
next;
|
|
}
|
|
push @uniq, $s;
|
|
}
|
|
@sym = @uniq;
|
|
|
|
$textend = $sym[-1][0] + 0x1000 unless $textend;
|
|
|
|
if ($list) {
|
|
printf "%016x %s\n", $_->[0], $_->[1] for @sym;
|
|
exit 0;
|
|
}
|
|
|
|
my $base = $sym[0][0];
|
|
for my $s (@sym) {
|
|
die sprintf("ksyms: symbol %s at %x is more than 4 GB above the base\n",
|
|
$s->[1], $s->[0])
|
|
if $s->[0] - $base > 0xffffffff;
|
|
}
|
|
|
|
# Offsets into the name blob, computed here so the kernel does not have to
|
|
# scan for NULs at boot.
|
|
my @off;
|
|
my $cur = 0;
|
|
for my $s (@sym) {
|
|
push @off, $cur;
|
|
$cur += length($s->[1]) + 1;
|
|
}
|
|
|
|
my $n = scalar @sym;
|
|
|
|
print <<"HDR";
|
|
// Generated by tools/ksyms.pl from the first link pass. Do not edit.
|
|
//
|
|
// See docs/architecture/debugging.md, milestone D0, and kernel/core/ksym.c for the
|
|
// lookup that reads this. Everything lands in .ksym, which kernel/kernel.ld
|
|
// places after .text and .rodata so that carrying the table cannot move the
|
|
// addresses recorded in it.
|
|
|
|
#include "types.h"
|
|
|
|
#define KSYM_SECTION __attribute__((section(".ksym"), used))
|
|
|
|
KSYM_SECTION const uint32 ksym_count = ${n}u;
|
|
KSYM_SECTION const uint64 ksym_base = 0x${\ sprintf("%x", $base) }ULL;
|
|
KSYM_SECTION const uint64 ksym_textend = 0x${\ sprintf("%x", $textend) }ULL;
|
|
|
|
// Offsets from ksym_base rather than absolute addresses: the kernel spans
|
|
// about a megabyte, so 32 bits is plenty and it halves the table.
|
|
KSYM_SECTION const uint32 ksym_addr[${n}] = {
|
|
HDR
|
|
|
|
for (my $i = 0; $i < $n; $i += 8) {
|
|
my $end = $i + 7; $end = $n - 1 if $end > $n - 1;
|
|
print " ", join(",", map { sprintf("0x%08x", $sym[$_][0] - $base) } ($i .. $end)), ",\n";
|
|
}
|
|
|
|
print "};\n\nKSYM_SECTION const uint32 ksym_nameoff[${n}] = {\n";
|
|
|
|
for (my $i = 0; $i < $n; $i += 8) {
|
|
my $end = $i + 7; $end = $n - 1 if $end > $n - 1;
|
|
print " ", join(",", map { sprintf("%6d", $off[$_]) } ($i .. $end)), ",\n";
|
|
}
|
|
|
|
print "};\n\nKSYM_SECTION const char ksym_names[] =\n";
|
|
|
|
for my $s (@sym) {
|
|
my $name = $s->[1];
|
|
$name =~ s/([\\"])/\\$1/g;
|
|
print " \"$name\\0\"\n";
|
|
}
|
|
|
|
print ";\n";
|