Initial commit

This commit is contained in:
Bahadir Balban
2008-01-13 13:53:52 +00:00
commit e2b791a3d8
789 changed files with 95825 additions and 0 deletions

861
tools/cml2-tools/autoconfigure.py Executable file
View File

@@ -0,0 +1,861 @@
#!/usr/bin/env python
#
# linux/scripts/autoconfigure.py : Automagical Kernel Configuration.
#
# Copyright (C) 2000-2002 Eric S. Raymond <esr@thyrsus.com>
# This is free software, see GNU General Public License 2 for details.
#
# This script tries to autoconfigure the Linux kernel, detecting the
# hardware (devices, ...) and software (protocols, filesystems, ...).
# It uses soft detection: no direct IO access to unknown devices, thus
# it is always safe to run this script and it never hangs, but it cannot
# detect all hardware (mainly misses some very old hardware). You don't
# need root, but you will need a CML2 rulebase handy.
#
# Most of the smarts in this script is in the file of probe rules
# maintained by Giacomo Catenazzi and brought in by execfile.
import sys, getopt, os, glob, commands, re
import cml, cmlsystem
from cml import y, m, n # For use in the autoprobe rules
lang = {
"COMPLETE":"Configuration complete.",
"COMPLEMENT":"* Computing complement sets",
"DERIVED":"Symbol %s is derived and cannot be set.",
"DONE":"Done",
"EFFECTS":"Side effects:",
"NOCMDLINE":"%s is the wrong type to be set from the command line",
"OPTUNKNOWN":"autoconfigure: unknown option.\n",
"ROOTFS":"* %s will be hard-compiled in for the root filesystem\n",
"ROOTHW":"* %s will be hard-compiled in to run the root device\n",
"ROOTLOOK":"# Looking for your root filesystem...\n",
"ROOTWARN":"** Warning: I could not identify the " \
"bus type of your root drive!\n",
"SETFAIL" : "%s failed while %s was being set to %s\n",
"SYMUNKNOWN":"cmlconfigure: unknown symbol %s\n",
"TURNOFF":"# Turning off unprobed device symbols",
"UNAME":"Can't determine ARCH, uname failed.",
}
class ConfigFile:
"Object that represents a generated configuration."
def __init__(self, myconfiguration, hardcompile, debuglevel=0):
# Prepare an output object to accept the configuration file
self.hardcompile = hardcompile
self.myconfiguration = myconfiguration
myconfiguration.debug = debuglevel
self.modified = {}
self.emitted = {}
if debuglevel:
sys.stderr.write("* Debug level %d" % debuglevel)
# 'found' sets the value 'y/m' (driver detected)
# 'found_y' sets the value 'y' (driver detected, forces built-in)
# 'found_m' sets the value 'm' (driver detected, build as module)
# 'found_n' sets the value 'n' (driver not needed)
#
# The priority is: y > m > n > 'other'
def found(self, symbol, val=None, label=None):
if type(symbol) == type(""):
symbol = self.myconfiguration.dictionary.get(symbol)
# Ignore obsolete symbols
if not symbol:
return
# Ignore attempts to set derived symbols. Some autoprobes
# do this because they were composed in ignorance of the rulebase.
elif symbol.is_derived():
return
# If no value specified, play some tricks.
if val == None:
if symbol.type=="bool" or (self.hardcompile and symbol.type=="trit"):
val = cml.y
elif symbol.type == "trit":
val = cml.m
elif symbol.is_numeric():
val = 0
elif symbol.type == "string":
val = ""
if not self.modified.has_key(symbol) or symbol.eval() < val:
self.myconfiguration.set_symbol(symbol, val)
self.modified[symbol] = 1
(ok, effects, violations) = self.myconfiguration.set_symbol(symbol, val)
if ok:
if label:
symbol.setprop(label)
else:
for violation in violations:
sys.stderr.write(lang["SETFAIL"] % (`violation`, symbol.name, val))
def found_y(self, var, label=None): self.found(var, cml.y, label)
def found_m(self, var, label=None): self.found(var, cml.m, label)
def found_n(self, var, label=None): self.found(var, cml.n, label)
def yak(self, symbol):
if not self.emitted.has_key(symbol):
try:
entry = self.myconfiguration.dictionary[symbol]
if entry.prompt:
sys.stderr.write("* " + symbol + ": " + entry.prompt + "\n")
self.emitted[symbol] = 1
except KeyError:
sys.stderr.write("! Obsolete symbol: " + symbol + "\n")
def complement(self, symbol, value, baton, label):
"Force a complement set to a specified value."
symbol = self.myconfiguration.dictionary[symbol]
if not symbol.eval():
return
for driver in self.myconfiguration.dictionary.values():
if baton: baton.twirl()
if driver.is_symbol() and driver.is_logical() \
and self.myconfiguration.is_visible(driver) \
and driver.setcount == 0 \
and symbol.ancestor_of(driver):
set_to = value
if driver.type == "bool" and value == cml.m:
set_to = cml.y
self.found(driver.name, set_to, label)
def force_dependents_modular(self, symbol, legend):
"Force all trit-valued dependents of a symbol to be modular."
net_ethernet = self.myconfiguration.dictionary[symbol]
for driver in self.myconfiguration.dictionary.values():
if driver.is_symbol() and driver.type == "trit" \
and driver.eval() == cml.y \
and self.myconfiguration.is_visible(driver) \
and net_ethernet.ancestor_of(driver):
driver.setprop(legend)
self.found(driver, cml.m)
def enabled(self, symbol):
"Is a given symbol enabled?"
return self.myconfiguration.dictionary[symbol]
# Now define classes for probing and reporting the system state
class PCIDevice:
"Identification data for a device on the PCI bus."
def __init__(self, procdata):
"Initialize PCI device ID data based on what's in a /proc entry."
procdata = map(ord, procdata)
self.vendor = "%02x%02x" % (procdata[1], procdata[0])
self.device = "%02x%02x" % (procdata[3], procdata[2])
if procdata[14]:
self.subvendor = None
self.subdevice = None
else:
self.subvendor = "%02x%02x" % (procdata[45], procdata[44])
self.subdevice = "%02x%02x" % (procdata[47], procdata[46])
self.revision = "%02x" % procdata[8]
self.deviceclass = "%02x%02x" % (procdata[11], procdata[10])
self.interface = "%02x" % procdata[9]
# Here is the digest format:
# "pci: xxxx,yyyy,zz:Class:aabb,cc" or
# "pci: xxxx,yyyy,ssss,rrrr,zz:Class:aabbb,cc"
# where: xxxx,yyyy: the vendor and device id
# ssss,rrrr: the sub-vendor and sub-device id
# zz: revision
# aabb,cc: Device Class, Interface
self.digest = self.vendor + "," + self.device
if self.subvendor:
self.digest += "," + self.subvendor + "," + self.subdevice
self.digest += ",%s;Class:%s,%s\n" % (self.revision,self.deviceclass,self.interface)
def __repr__(self):
return "pci: " + self.digest
class PCIScanner:
"Encapsulate the PCI hardware registry state."
def __init__(self):
"Unpack data from the PCI hardware registry."
self.devices = []
for f in glob.glob("/proc/bus/pci/??/*"):
dfp = open(f)
self.devices.append(PCIDevice(dfp.read()))
dfp.close()
def search(self, pattern):
"Search for a device match by prefix in the digest."
pattern = re.compile(pattern, re.I)
return not not filter(lambda x, p=pattern: p.search(x.digest), self.devices)
def __repr__(self):
return "".join(map(repr, self.devices))
class FieldParser:
"Parse entire lines, or a given field, out of a file or command output."
def __init__(self, sources):
self.items = []
for item in sources:
if type(item) == type(()):
file = item[0]
field = item[1]
else:
file = item
field = None
try:
if file[0] == '/':
ifp = open(file, "r")
lines = ifp.readlines()
ifp.close()
else:
(status, output) = commands.getstatusoutput(file)
if status:
raise IOError
lines = output.split("\n")
except IOError:
continue
# No field specified, capture entire line
if not field:
self.items += lines
# Numeric (1-origin) field index, capture that
# space-separated field.
elif type(field) == type(0):
for line in lines:
fields = line.split()
if len(fields) >= field and fields[field-1] not in self.items:
self.items.append(fields[field-1])
# Regexp specified, collect group 1
else:
for line in lines:
lookfor = re.compile(field)
match = lookfor.search(line)
if match:
res = match.group(1)
if res not in self.items:
self.items.append(res)
def find(self, str, ind=0):
"Is given string or regexp pattern found in the file?"
match = re.compile(str)
result = filter(lambda x: x, map(lambda x, ma=match: ma.search(x), self.items))
if result:
result = result[ind]
if result.groups():
result = ",".join(result.groups())
return result
def __repr__(self):
return `self.items`
#
# Main sequence begins here
#
def get_arch():
# Get the architecture (taken from top-level Unix makefile).
(error, ARCH) = commands.getstatusoutput('uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/')
if error:
sys.stderr.write(lang["UNAME"])
raise SystemExit, 1
# A platform symbol has to be set, otherwise many assignments will fail
ARCHSYMBOL = re.compile("i.86").sub("x86", ARCH)
ARCHSYMBOL = ARCHSYMBOL.replace("superh", "sh")
ARCHSYMBOL = ARCHSYMBOL.replace("sparc32", "sparc")
ARCHSYMBOL = ARCHSYMBOL.replace("sparc64", "sparc")
ARCHSYMBOL = ARCHSYMBOL.upper()
return(ARCH, ARCHSYMBOL)
# We can't assume 2.1 nested scopes, so refer shared stuff to global level.
config = cpu = cpu_id = pci = isapnp = mca = usbp = usbc = usbi = None
fs = devices = m_devices = misc = net = ide = dmesg = None
modules = cpu_latch = None
fsmap = {}
reliable = {}
def autoconfigure(configuration, hardcompile, debuglevel):
global config, cpu, cpu_id, pci, isapnp, mca, usbp, usbc, usbi, fs
global devices, m_devices, misc, net, ide, dmesg, modules, cpu_latch
global fsmap, reliable
configuration.interactive = 0 # Don't deduce from visibility.
config = ConfigFile(configuration, hardcompile, debuglevel)
#
# Here is where we query the system state.
#
(ARCH, ARCHSYMBOL) = get_arch()
config.found_y(ARCHSYMBOL)
config.yak(ARCHSYMBOL)
# Get the processor type
cpu = FieldParser(("/proc/cpuinfo",))
if ARCHSYMBOL == 'SPARC':
processors = int(cpu.find("^ncpus active.*: *([0-9]*)"))
vendor = cpu.find("^cpu.*: *(.*)")
cpufam = cpu.find("^type.*: *([-A-Za-z0-9_]*)")
mod = cpu.find("^fpu.*: *(.*)")
name = cpu.find("^MMU Type.*: *(.*)")
else:
processors = int(cpu.find("^processor.*: *([0-9]*)", -1)) + 1
vendor = cpu.find("^vendor_id.*: *([-A-Za-z0-9_]*)")
cpufam = cpu.find("^cpu family.*: *([-A-Za-z0-9_]*)")
mod = cpu.find("^model.*: *([-A-Za-z0-9_]*)")
name = cpu.find("^model name.*: *(.*)")
cpu_id = vendor + ":" + cpufam + ":" + mod + ":" + name
cpu_latch = 0
# Now query for features
pci = PCIScanner()
isapnp = FieldParser((("/proc/bus/isapnp/devices", 2),))
mca = FieldParser(("/proc/mca/pos",))
usbp = FieldParser((("/proc/bus/usb/devices", "^P:.*Vendor=([A-Fa-f0-9]*)\s.*ProdID=\([A-Fa-f0-9]*\)"),))
usbc = FieldParser((("/proc/bus/usb/devices", "^D:.*Cls=([A-Fa-f0-9]*)[^A-Fa-f0-9].*Sub=([A-Fa-f0-9]*)[^A-Fa-f0-9].*Prot=([A-Fa-f0-9]*)"),))
usbi = FieldParser((("/proc/bus/usb/devices", "^I:.*Cls=([A-Fa-f0-9]*)[^A-Fa-f0-9].*Sub=([A-Fa-f0-9]*)[^A-Fa-f0-9].*Prot=([A-Fa-f0-9]*)"),))
fs = FieldParser((("/proc/mounts",3),
("/etc/mtab", 3),
("/etc/fstab", 3)))
devices = FieldParser((("/proc/devices", "[0-9]+ (.*)"),))
m_devices = FieldParser((("/proc/misc", "[0-9]+ (.*)"),))
misc = FieldParser(("/proc/iomem", "/proc/ioports", "/proc/dma", "/proc/interrupts"))
net = FieldParser((("/proc/net/sockstat","^([A-Z0-9]*): inuse [1-9]"),))
ide = FieldParser(glob.glob('/proc/ide/hd?/media'))
dmesg = FieldParser(("/var/log/dmesg", "dmesg"))
modules = FieldParser((("/proc/modules", 1),))
#
# Tests that won't fit in the rulesfile format
#
# Source: linux/i386/kernel/setup.c
if dmesg.find("Use a PAE"):
config.found_y("HIGHMEM64G")
elif dmesg.find("Use a HIGHMEM"):
config.found_y("HIGHMEM4G") ##Source: linux/i386/kernel/setup.c
else:
highmem = dmesg.find("([0-9]*)MB HIGHMEM avail.")
if not highmem:
config.found_y("NOHIGHMEM")
elif int(highmem) > 3072:
config.found_y("HIGHMEM64G")
else:
config.found_y("HIGHMEM4G")
# SMP? This test is reliable.
if processors == 0:
processors = len(filter(lambda x: x.find('processor') > -1, cpu.items))
if processors > 1:
config.found_y("SMP")
config.yak("SMP")
fsmap = {}
reliable = {}
#
# Here are the function calls used by the rules file
#
TRUE = 1
FALSE = 0
PRESENT = 1
ABSENT = 0
def DEBUG(str):
sys.stderr.write("# " + str + "\n")
# Following three tests are reliable -- that is, if PCI or PNP
# tests fail we know the feature is *not* there.
def PCI(prefix, symbol):
global pci, config
reliable[symbol] = "PCI"
if pci.search("^" + prefix):
config.yak(symbol)
config.found(symbol, None, "PCI")
def PCI_CLASS(match, symbol):
global pci, config
reliable[symbol] = "PCI_CLASS"
if pci.search("Class:" + match):
config.yak(symbol)
config.found(symbol, None, "PCI_CLASS")
def PNP(match, symbol):
global isapnp, config
reliable[symbol] = "PNP"
if isapnp.find(match):
config.yak(symbol)
config.found(symbol, None, "PNP")
def MCA(match, symbol):
global mca, config
reliable[symbol] = "MCA"
# FIXME: Not certain I've got the byte order right here
if mca.find(": " + match[2:] + " " + match[:2]):
config.yak(symbol)
config.found(symbol, None, "MCA")
# USB tests reliably detect connected devices, but the bus is hot-plug.
def USBP(match, symbol):
global usbp, config
if usbp.find(match):
config.yak(symbol)
config.found(symbol, None, "USBP")
def USBC(match, symbol):
global usbc, config
if usbc.find(match):
config.yak(symbol)
config.found(symbol, None, "USBC")
def USBI(match, symbol):
global usbi, config
if usbi.find(match):
config.yak(symbol)
config.found(symbol, None, "USBI")
# Remaining tests rely on prior kernel configuration.
def FS(match, symbol):
global fs, fsmap, config
if fs.find(r"\b" + match + r"\b"):
config.yak(symbol)
config.found(symbol, None, "FS")
# Also, build the map of file system types to symbols.
fsmap[match] = symbol
def DEV(match, symbol):
global devices, config
if devices.find(r"\b" + match + r"\b"):
config.yak(symbol)
config.found(symbol, None, "DEV")
def DEVM(match, symbol):
global m_devices, config
if m_devices.find(r"\b" + match + r"\b"):
config.yak(symbol)
config.found(symbol, None, "DEV_M")
def CONS(match, symbol):
global dmesg, config
if dmesg.find("^Console: .* " + match + " "):
config.yak(symbol)
config.found(symbol, None, "CONS")
def DMESG(match, symbol, truthval=TRUE):
global dmesg, config
if dmesg.find(match):
if truthval:
config.found(symbol, None, "DMESG")
config.yak(symbol)
else:
config.found_n(symbol, "DMESG")
def NET(match, symbol):
global net, config
if net.find(match):
config.yak(symbol)
config.found(symbol, None, "NET")
def IDE(match, symbol):
global ide, config
if ide.find(match):
config.yak(symbol)
config.found(symbol, None, "IDE")
def REQ(match, symbol):
global misc, config
if misc.find(match):
config.yak(symbol)
config.found(symbol, None, "REQ")
def CPUTYPE(match, symbol):
global cpu_latch, config
if not cpu_latch and re.search(match, cpu_id):
config.found_y(symbol, "CPUTYPE")
config.yak(symbol)
cpu_latch = 1
def CPUINFO(match, symbol, present=PRESENT, truthval=cml.y):
global cpu, config
if (not not cpu.find(match)) == present:
config.found(symbol, truthval, "CPUINFO")
if truthval:
config.yak(symbol)
def EXISTS(procfile, symbol):
global config
if os.path.exists(procfile):
config.found(symbol, None, "EXISTS")
config.yak(symbol)
else:
config.found(symbol, n, "EXISTS")
def MODULE(name, symbol):
global modules, config
if modules.find(r"\b" + name + r"\b"):
config.found(symbol, None, "MODULES")
config.yak(symbol)
def GREP(pattern, file, symbol):
global config
try:
fp = open(file)
except IOError:
return
if re.compile(pattern).search(fp.read()):
config.found(symbol, None, "GREP")
config.yak(symbol)
fp.close()
def LINKTO(file, pattern, symbol):
global config
if not os.path.exists(file):
return
file = os.readlink(file)
if re.compile(pattern).search(file):
config.found(symbol, None, "LINKTO")
config.yak(symbol)
# Use this to avoid conflicts
def PRIORITY(symbols, cnf=configuration):
global config
legend = "PRIORITY" + `symbols`
dict = cnf.dictionary
symbols = map(lambda x, d=dict: d[x], symbols)
for i in range(len(symbols) - 1):
if cml.evaluate(symbols[i]):
for j in range(i+1, len(symbols)):
cnf.set_symbol(symbols[j], n)
symbols[j].setprop(legend)
break
########################################################################
##
## Section Command Version Status
## ------------------------------------------------------------------
## /proc features EXISTS 2.5.2-pre7 Partial
########################################################################
## Section: System Features
## KernelOutput: /proc/*, /dev/*
## Detect system features based on existence of /proc and /dev/* files
DEBUG("autoconfigure.rules: EXISTS")
## These tests are unreliable; they depend on the current kernel config.
EXISTS("/proc/sysvipc", 'SYSVIPC')
EXISTS("/proc/sys", 'SYSCTL')
EXISTS("/proc/scsi/ide-scsi", 'BLK_DEV_IDESCSI')
EXISTS("/proc/scsi/imm", 'SCSI_IMM')
EXISTS("/proc/scsi/ppa", 'SCSI_PPA')
EXISTS("/dev/.devfsd", 'DEVFS_FS')
# Giacomo does not have these yet.
EXISTS("/proc/sys/net/khttpd", 'KHTTPD')
EXISTS("/proc/sys/kernel/acct", 'BSD_PROCESS_ACCT')
# This one is reliable, according to the MCA port documentation.
EXISTS("/proc/mca", 'MCA')
# This one is reliable too
EXISTS("/proc/bus/isapnp/devices", 'ISAPNP')
# Test the new probe function.
GREP("scsi0", "/proc/scsi/scsi", 'SCSI')
# These can be bogus because the file or directory in question
# is empty, or consists of a banner string that does not describe
# an actual device. We need to do more analysis here.
# EXISTS("/proc/bus/pci", 'PCI')
# EXISTS("/proc/bus/usb", 'USB')
# EXISTS("/proc/net", 'NET')
# EXISTS("/proc/scsi", 'SCSI')
# These look tempting, but they're no good unless we're on a pure
# devfs system, without support for old devices, where devices
# only exist when they're needed.
# EXISTS("/dev/agpgart", 'AGP')
# EXISTS("/dev/floppy", 'BLK_DEV_FD')
# EXISTS("/dev/fd0", 'BLK_DEV_FD')
########################################################################
## Section: Mice
## Detect the mouse type by looking at what's behind the /dev/mouse link.
## These are probes for 2.4 with the old input core
LINKTO("/dev/mouse", "psaux", 'PSMOUSE')
LINKTO("/dev/mouse", "ttyS", 'SERIAL')
LINKTO("/dev/mouse", "logibm", 'LOGIBUSMOUSE')
LINKTO("/dev/mouse", "inportbm", 'MS_BUSMOUSE')
LINKTO("/dev/mouse", "atibm", 'ATIXL_BUSMOUSE')
## These are probes for 2.5 with the new input core
LINKTO("/dev/mouse", "psaux", 'MOUSE_PS2')
LINKTO("/dev/mouse", "ttyS", 'MOUSE_SERIAL')
LINKTO("/dev/mouse", "logibm", 'MOUSE_LOGIBM')
LINKTO("/dev/mouse", "inportbm", 'MOUSE_INPORT')
LINKTO("/dev/mouse", "atibm", 'MOUSE_ATIXL')
########################################################################
## Section: IDE devices
## KernelOutput: /proc/ide/hd?/media
## Detect IDE devices based on contents of /proc files
## These tests are unreliable; they depend on the current kernel config.
IDE('disk', 'BLK_DEV_IDEDISK')
IDE('cdrom', 'BLK_DEV_IDECD')
IDE('tape', 'BLK_DEV_IDETAPE')
IDE('floppy', 'BLK_DEV_FLOPPY')
EXISTS("/dev/ide/ide0", 'BLK_DEV_IDE')
EXISTS("/dev/ide/ide1", 'BLK_DEV_IDE')
EXISTS('/proc/ide/piix', 'PIIX_TUNING')
########################################################################
# Miscellaneous tests that replace Giacomo's ad-hoc ones.
DEV('pty', 'UNIX98_PTYS')
REQ('SMBus', 'I2C')
REQ('ATI.*Mach64', 'FB_ATY')
#FS(r'xfs', 'XFS_FS')
########################################################################
# This is a near complete set of MCA probes for hardware supported under
# Linux, according to MCA maintainer David Weinehall. The exception is
# the IBMTR card, which cannot be probed reliably.
if config.enabled("MCA"):
MCA("ddff", 'BLK_DEV_PS2')
MCA("df9f", 'BLK_DEV_PS2')
MCA("628b", 'EEXPRESS')
MCA("627[cd]", 'EL3')
MCA("62db", 'EL3')
MCA("62f6", 'EL3')
MCA("62f7", 'EL3')
MCA("6042", 'ELMC')
MCA("0041", 'ELMC_II')
MCA("8ef5", 'ELMC_II')
MCA("61c[89]", 'ULTRAMCA')
MCA("6fc[012]", 'ULTRAMCA')
MCA("efd[45]", 'ULTRAMCA')
MCA("efe5", 'ULTRAMCA')
MCA("641[036]", 'AT1700')
MCA("6def", 'DEPCA')
MCA("6afd", 'SKMC')
MCA("6be9", 'SKMC')
MCA("6354", 'NE2_MCA')
MCA("7154", 'NE2_MCA')
MCA("56ea", 'NE2_MCA')
MCA("ffe0", 'IBMLANA')
MCA("8ef[8cdef]", 'SCSI_IBMMCA')
MCA("5137", 'SCSI_FD_MCS')
MCA("60e9", 'SCSI_FD_MCS')
MCA("6127", 'SCSI_FD_MCS')
MCA("0092", 'SCSI_NCR_D700')
MCA("7f4c", 'SCSI_MCA_53C9X')
MCA("0f1f", 'SCSI_AHA_1542')
MCA("002d", 'MADGEMC')
MCA("6ec6", 'SMCTR')
MCA("62f3", 'SOUND_SB')
MCA("7113", 'SOUND_SB')
########################################################################
## This requires Paul Gortmaker's EISA ID patch.
REQ("EISA", "EISA") # Someday, IOPORTS()
########################################################################
## The rest of the table is read in from Giacomo's Catenazzi's rulesfile.
execfile(rulesfile)
# If it has a reliable test, but was not found by any test, switch it off.
# We do things in this order to avoid losing on symbols that are only set
# to n by PNP and PCI tests.
baton = cml.Baton(lang["TURNOFF"])
for symbol in configuration.dictionary.values():
baton.twirl()
if symbol.is_symbol() and configuration.saveable(symbol) \
and reliable.has_key(symbol.name) and not cml.evaluate(symbol):
config.found(symbol.name, n, reliable[symbol.name])
baton.end()
########################################################################
## Resolve conflicts.
PRIORITY(("SCSI_SYM53C8XX_2", "SCSI_SYM53C8XX", \
"SCSI_NCR53C8XX", "SCSI_GENERIC_NCR5380"))
PRIORITY(("DE2104X", "TULIP"))
## End of probe logic.
##
########################################################################
# More tests that don't fit the rulesfile format
# Filesystem, bus, and controller for root cannot be modules.
sys.stderr.write(lang["ROOTLOOK"])
fstab_to_bus_map = {
r"^/dev/sd" : ("SCSI",),
r"^/dev/hd" : ("IDE",),
r"\bnfs\b" : ("NFS_FS", "NFS_ROOT", "NET"),
}
ifp = open("/etc/mtab", "r")
while 1:
line = ifp.readline()
if not line:
break
fields = line.split()
mountpoint = fields[1]
fstype = fields[2]
if mountpoint == "/":
# Figure out the drive type of the root partition.
rootsymbols = []
for (pattern, symbols) in fstab_to_bus_map.items():
if re.compile(pattern).search(line):
rootsymbols = list(symbols)
if fsmap.has_key(fstype):
rootsymbols.append(fsmap[fstype])
if not rootsymbols:
sys.stderr.write(lang["ROOTWARN"])
break
# We should have a list of `buses' now...
for roottype in rootsymbols:
# First we have to force the bus the drive is on to y.
config.found(roottype, y, "Root filesystem")
sys.stderr.write(lang["ROOTFS"] % roottype)
# Then force all bootable hardware previously set modular and
# dependent on this bus to y.
bus = configuration.dictionary[roottype]
for symbol in configuration.dictionary.values():
if cml.evaluate(symbol) == m \
and symbol.hasprop("BOOTABLE") \
and bus.ancestor_of(symbol):
config.found(symbol.name, y, "Root filesystem")
sys.stderr.write(lang["ROOTHW"] % symbol.name)
ifp.close()
# PTY devices
ptycount = dmesg.find('pty: ([0-9]*) Unix98 ptys')
if ptycount:
config.found("UNIX98_PTY_COUNT", int(ptycount))
# Helper functions.
def grepcmd(pattern, cmd):
"Test for PATTERN in the output of COMMAND."
(status, output) = commands.getstatusoutput(cmd)
return status == 0 and re.compile(pattern).search(output)
# Apply those sanity checks
# Handle a subtle gotcha: if there are multiple NICs, they must be modular.
if grepcmd("eth[1-3]", "/sbin/ifconfig -a"):
config.force_dependents_modular("NET_ETHERNET",
"Multiple NICs must be modular")
# Now freeze complement sets. With any luck, this will reduce the
# set of drivers the user actually has to specify to zero.
#
# Giacomo writes:
# "BTW I have done some test with USB, and it seems that you can
# hotplug USB devices, also with hardcored drivers, and the driver
# is initialized only at the hotplug event.
# (This mean that USB devices can be set also to 'y', without
# losing functionality.
# This is not true for other 'hotplug' devices. I.e. my
# parport ZIP will be loaded only at boot time (hardcoded) or
# at modules loading (module)."
#
# So far I have not done anything about this.
if not hardcompile:
b = cml.Baton(lang["COMPLEMENT"])
config.complement("HOTPLUG_PCI",cml.m, b, "PCI_HOTPLUG is a hot-plug bus")
config.complement("USB", cml.m, b, "USB is a hot-plug bus")
config.complement("PCMCIA", cml.m, b, "PCMCIA is a hot-plug bus")
config.complement("IEEE1394", cml.m, b, "IEEE1394 ia a hot-plug bus")
b.end(lang["DONE"])
DEBUG(lang["COMPLETE"])
def process_define(myconfiguration, val, freeze):
"Process a -d=xxx or -D=xxx option."
parts = val.split("=")
sym = parts[0]
if myconfiguration.dictionary.has_key(sym):
sym = myconfiguration.dictionary[sym]
else:
myconfiguration.errout.write(lang["SYMUNKNOWN"] % (`sym`,))
sys.exit(1)
if sym.is_derived():
myconfiguration.debug_emit(1, lang["DERIVED"] % (`sym`,))
sys.exit(1)
elif sym.is_logical():
if len(parts) == 1:
val = 'y'
elif parts[1] == 'y':
val = 'y'
elif parts[1] == 'm':
myconfiguration.trits_enabled = 1
val = 'm'
elif parts[1] == 'n':
val = 'n'
elif len(parts) == 1:
print lang["NOCMDLINE"] % (`sym`,)
sys.exit(1)
else:
val = parts[1]
(ok, effects, violation) = myconfiguration.set_symbol(sym,
myconfiguration.value_from_string(sym, val),
freeze)
if effects:
sys.stderr.write(lang["EFFECTS"] + "\n")
sys.stderr.write("\n".join(effects) + "\n\n")
if not ok:
sys.stderr.write((lang["ROLLBACK"] % (sym.name, val)) + "\n")
sys.stderr.write("\n".join(violation)+"\n")
if __name__ == "__main__":
# Process command-line options
try:
(options, arguments) = getopt.getopt(sys.argv[1:], "d:D:hr:st:v",
("hardcompile",
"rules=",
"standalone",
"target=",
"verbose"))
except getopt.GetoptError:
sys.stderr.write(lang["OPTUNKNOWN"])
raise SystemExit, 2
autoprobe_debug = hardcompile = standalone = 0
objtree = os.environ.get("KBUILD_OBJTREE")
rulesfile = "autoconfigure.rules"
freeze_em = []
set_em = []
for (opt, val) in options:
if opt == '-D':
freeze_em.append(val)
elif opt == '-d':
set_em.append(val)
elif opt in ("-v", "--verbose"):
autoprobe_debug += 1
elif opt in ("--hardcompile", "-h"):
hardcompile = 1
elif opt in ("--rules", "-r"):
rulesfile = val
elif opt in ("--standalone", "-s"):
standalone = 1
elif opt in ("--target", "-t"):
objtree = os.path.expanduser(val)
if objtree == None:
objtree = "."
#
# Now use the rulebase information
#
rulebase = os.path.join(objtree, "rules.out")
if not os.path.exists(rulebase):
sys.stderr.write("autoconfigure: rulebase %s does not exist!\n" % rulebase)
raise SystemExit, 1
configuration = cmlsystem.CMLSystem(rulebase)
if not cmlsystem:
sys.stderr.write("autoconfigure: rulebase %s could not be read!\n" % rulebase)
raise SystemExit, 1
# Autoconfigure into the configuration object.
for sym in freeze_em:
process_define(configuration, sym, 1)
for sym in set_em:
process_define(configuration, sym, 0)
autoconfigure(configuration, hardcompile, autoprobe_debug)
# Write out this configuration, we're done.
if standalone:
configuration.save(sys.stdout, None, "normal")
else:
configuration.save(sys.stdout, None, "probe")
# End

438
tools/cml2-tools/cml.py Executable file
View File

@@ -0,0 +1,438 @@
"""
cml.py -- types for communication between CML2 compiler and configurators.
"""
import sys, os, time
version="2.3.0"
class trit:
"A boolean or trit value"
type = "trit"
def __init__(self, value):
if isinstance(value, trit):
value = value.value
self.value = value
def __repr__(self):
return "nmy"[self.value]
def __nonzero__(self):
return self.value
def __hash__(self):
return self.value # This magic needed to make trits valid dictionary keys
def __long__(self):
return self.value != 0
def __cmp__(self, other):
if not isinstance(other, trit):
if other is None:
return 1 # any trit > None
else: # Standard no-__cmp__ behavior=20
if id(self) < id(other):
return -1
elif id(self) > id(other):
return 1
else:
return 0
else:
diff = self.value - other.value
if diff == 0:
return 0
else:
return diff / abs(diff)
def __and__(self, other):
return trit(min(self.value, other.value))
def __or__(self, other):
return trit(max(self.value, other.value))
def eval(self):
return self
# Trit value constants
y = trit(2)
m = trit(1)
n = trit(0)
# This describes a configuration symbol...
class ConfigSymbol:
"Compiled information about a menu or configuration symbol"
def __init__(self, name, type=None, default=None, prompt=None, file=None, lineno=None):
# Name, location, type, default.
self.name = name
self.file = file # Definition location source file
self.lineno = lineno # Definition location source line
self.type = type # Type of symbol
self.range = None # Range tuple
self.enum = None
self.discrete = None
self.helptext = None # Help reference
self.default = default # Value to use if none has been set.
# Hierarchy location
self.ancestors = [] # Ancestors of symbol (as set up by {})
self.dependents = [] # Dependents of symbol (as set up by {})
self.choicegroup = [] # Other symbols in a choicegroup.
self.menu = None # Unique parent menu of this symbol
self.depth = 0 # Nesting depth in its subtree
# Auxiliary information
self.prompt = prompt # Associated question string
self.properties = {} # Associated properties
self.warnings = [] # Attached warndepend conditions
self.visibility = None # Visibility predicate for symbol
self.saveability = None # Saveability predicate for symbol
self.items = [] # Menus only -- associated symbols
# Compiler never touches these
self.visits = 0 # Number of visits so far
self.setcount = 0 # Should this symbol be written?
self.included = 0 # Seen in an inclusion?
self.inspected = 0 # Track menu inspections
self.iced = 0 # Is this frozen?
# Compute the value of a symbol
def eval(self, debug=0):
"Value of symbol; passes back None if the symbol is unset."
if self.default is not None:
result = evaluate(self.default, debug)
# Handle casting. This can matter in derivations
if self.type == "bool":
if isinstance(result, trit):
result = trit(y.value * (result != n))
elif type(result) == type(0):
result = trit(y.value * (result != 0))
elif self.type in ("decimal", "hexadecimal"):
if isinstance(result, trit):
result = (result != n)
if debug > 3:
sys.stderr.write("...eval(%s)->%s (through default %s)\n" % \
(`self`, result, self.default))
return result
else:
if debug > 2:
sys.stderr.write("...eval(%s)->None (default empty)\n" % \
(`self`))
return None
# Access to help.
#
# This is the only place in the front end that knows about the CML1
# helpfile conventions.
def help(self):
"Is there help for the given symbol?"
if self.helptext:
return self.helptext
# Next five lines implement the CML1 convention for choices help;
# attach it to the first alternative. But they check for help
# attached to the symbol itself first.
if self.menu and self.menu.type == "choices":
self = self.menu
if self.type == "choices" and not self.helptext:
self = self.items[0]
return self.helptext
def ancestor_of(self, entry):
"Test transitive completion of dependency."
# We don't also check visibility, because visibility guards can have
# disjunctions and it would be wrong to propagate up both branches.
if entry.menu:
searchpath = entry.ancestors + [entry.menu]
else:
searchpath = entry.ancestors
if self in searchpath:
return 1
for x in searchpath:
if self.ancestor_of(x):
return 1
return 0
# Predicates
def is_derived(self):
"Is this a derived symbol?"
return self.prompt is None
def is_logical(self):
"Is this a logical symbol?"
return self.type in ("bool", "trit")
def is_numeric(self):
"Is this a numeric symbol?"
return self.type in ("decimal", "hexadecimal")
def is_symbol(self):
"Is this a real symbol? (not a menu, not a choices, not a message)"
return self.type in ("bool","trit", "decimal","hexadecimal", "string")
# Property functions
def hasprop(self, prop):
return self.properties.has_key(prop)
def setprop(self, prop, val=1):
self.properties[prop] = val
def delprop(self, prop):
del self.properties[prop]
def showprops(self,):
return ", ".join(self.properties.keys())
def __repr__(self):
# So the right thing happens when we print symbols in expressions
return self.name
def dump(self):
if self.prompt:
res = "'%s'" % self.prompt
else:
res = "derived"
res += ", type %s," % self.type
if self.range:
res = res + " range %s," % (self.range,)
if self.menu:
res = res + " in %s," % (self.menu.name,)
if self.ancestors:
res = res + " under %s," % (self.ancestors,)
if self.dependents:
res = res + " over %s," % (self.dependents,)
if self.choicegroup:
res = res + " choicegroup %s," % (self.choicegroup,)
if self.visibility is not None:
res = res + " visibility %s," % (display_expression(self.visibility),)
if self.saveability is not None:
res = res + " saveability %s," % (display_expression(self.saveability),)
if self.default is not None:
res = res + " default %s," % (`self.default`,)
if self.items:
res = res + " items %s," % (self.items,)
if self.properties:
res = res + " props=%s," % (self.showprops(),)
if self.file and self.lineno is not None:
res = res + " where=%s:%d," % (self.file, self.lineno)
return res
def __str__(self):
# Note that requirements are not shown
res = "%s={" % (self.name)
res = res + self.dump()
return res[:-1] + "}"
class Requirement:
"A requirement, together with a message to be shown if it's violated."
def __init__(self, wff, message, file, line):
self.predicate = wff
self.message = message
self.file = file
self.line = line
def str(self):
return display_expression(self.predicate)[1:-1]
def __repr__(self):
bindings = ""
for sym in flatten_expr(self.predicate):
bindings += "%s=%s, " % (sym.name, evaluate(sym))
bindings = bindings[:-2]
leader = '"%s", line %d: ' % (self.file, self.line)
if self.message:
return leader + self.message + " (" + bindings + ")"
else:
return leader + display_expression(self.predicate) + " (" + bindings + ")"
# This describes an entire configuration.
class CMLRulebase:
"A dictionary of ConfigSymbols and a set of constraints."
def __init__(self):
self.version = version
self.start = None # Start menu name
self.dictionary = {} # Configuration symbols
self.prefix = "" # Prepend this to all symbols
self.banner = "" # ID the configuration domain
self.constraints = [] # All requirements
self.icon = None # Icon for this rulebase
self.trit_tie = None # Are trits enabled?
self.help_tie = None # Help required for visibility?
self.expert_tie = None # Expert flag for UI control
self.reduced = []
def __repr__(self):
res = "Start menu = %s\n" % (self.start,)
for k in self.dictionary.keys():
res = res + str(self.dictionary[k]) + "\n"
if self.prefix:
res = res + "Prefix:" + `self.prefix`
if self.banner:
res = res + "Banner:" + `self.banner`
return res
def optimize_constraint_access(self):
"Assign constraints to their associated symbols."
for entry in self.dictionary.values():
entry.constraints = []
for requirement in self.reduced:
for symbol in flatten_expr(requirement):
if not requirement in symbol.constraints:
symbol.constraints.append(requirement)
# These functions are used by both interpreter and compiler
def evaluate(exp, debug=0):
"Compute current value of an expression."
def tritify(x):
if x:
return y
else:
return n
if debug > 2:
sys.stderr.write("evaluate(%s) begins...\n" % (`exp`,))
if type(exp) is type(()):
# Ternary operator
if exp[0] == '?':
guard = evaluate(exp[1], debug)
if guard:
return evaluate(exp[2], debug)
else:
return evaluate(exp[3], debug)
# Logical operations -- always trit-valued
elif exp[0] == 'not':
return tritify(not evaluate(exp[1], debug))
elif exp[0] == 'or':
return tritify(evaluate(exp[1], debug) or evaluate(exp[2], debug))
elif exp[0] == 'and':
return tritify(evaluate(exp[1], debug) and evaluate(exp[2], debug))
elif exp[0] == 'implies':
return tritify(not ((evaluate(exp[1], debug) and not evaluate(exp[2], debug))))
elif exp[0] == '==':
return tritify(evaluate(exp[1], debug) == evaluate(exp[2], debug))
elif exp[0] == '!=':
return tritify(evaluate(exp[1], debug) != evaluate(exp[2], debug))
elif exp[0] == '<=':
return tritify(evaluate(exp[1], debug) <= evaluate(exp[2], debug))
elif exp[0] == '>=':
return tritify(evaluate(exp[1], debug) >= evaluate(exp[2], debug))
elif exp[0] == '<':
return tritify(evaluate(exp[1], debug) < evaluate(exp[2], debug))
elif exp[0] == '>':
return tritify(evaluate(exp[1], debug) > evaluate(exp[2], debug))
# Arithmetic operations -- sometimes trit-valued
elif exp[0] == '|':
return evaluate(exp[1], debug) | evaluate(exp[2], debug)
elif exp[0] == '&':
return evaluate(exp[1], debug) & evaluate(exp[2], debug)
elif exp[0] == '$':
left = evaluate(exp[1])
right = evaluate(exp[2])
if left != right:
return n
else:
return left
elif exp[0] == '+':
return long(evaluate(exp[1],debug)) + long(evaluate(exp[2],debug))
elif exp[0] == '-':
return long(evaluate(exp[1],debug)) - long(evaluate(exp[2],debug))
elif exp[0] == '*':
return long(evaluate(exp[1],debug)) * long(evaluate(exp[2],debug))
else:
raise SyntaxError, "Unknown operation %s in expression" % (exp[0],)
elif isinstance(exp, trit) or type(exp) in (type(""), type(0), type(0L)):
if debug > 2:
sys.stderr.write("...evaluate(%s) returns itself\n" % (`exp`,))
return exp
elif isinstance(exp, ConfigSymbol):
result = exp.eval(debug)
if result:
return result
else:
return n
else:
raise ValueError,"unknown object %s %s in expression" % (exp,type(exp))
def flatten_expr(node):
"Flatten an expression -- skips the operators"
if type(node) is type(()) or type(node) is type([]):
sublists = map(flatten_expr, node)
flattened = []
for item in sublists:
flattened = flattened + item
return flattened
elif isinstance(node, ConfigSymbol):
if node.is_derived():
return flatten_expr(node.default)
else:
return [node]
else:
return []
def display_expression(exp):
"Display an expression in canonicalized infix form."
if type(exp) is type(()):
if exp[0] == "not":
return "not " + display_expression(exp[1])
elif exp[0] == '?':
return "(%s ? %s : %s)" % (display_expression(exp[1]), display_expression(exp[2]), display_expression(exp[3]))
else:
return "(%s %s %s)" % (display_expression(exp[1]), exp[0], display_expression(exp[2]))
elif isinstance(exp, ConfigSymbol):
return exp.name
else:
return `exp`
class Baton:
"Ship progress indication to stdout."
def __init__(self, prompt, endmsg=None):
if os.isatty(1):
self.stream = sys.stdout
elif os.isatty(2):
self.stream = sys.stderr
else:
self.stream = None
if self.stream:
self.stream.write(prompt + "... \010")
self.stream.flush()
self.count = 0
self.endmsg = endmsg
self.time = time.time()
return
def twirl(self, ch=None):
if self.stream is None:
return
if ch:
self.stream.write(ch)
else:
self.stream.write("-/|\\"[self.count % 4])
self.stream.write("\010")
self.count = self.count + 1
self.stream.flush()
return
def end(self, msg=None):
if msg == None:
msg = self.endmsg
if self.stream:
self.stream.write("...(%2.2f sec) %s.\n" % (time.time() - self.time, msg))
return
if __name__ == "__main__":
# Two classes without __cmp__
class A:
pass
class B:
pass
a = A()
b = B()
t0 = trit(0)
t1 = trit(1)
t2 = trit(2)
if not (t0 < t1 < t2 and t2 > t1 > t0) or t0 == t1 or t0 == t2 or t1 == t2:
print "trit compare failed"
if t0 < None:
print "a trit is less than None? Comparison failed"
if None > t0:
print "None is greater than a trit? Comparison failed"
if id(a) > id(b):
if a < b > a:
print "a/b comparison failed"
elif b < a > b:
print "a/b comparison failed"
# Simulate standard no-cmp() behavior for non-trits
if id(a) > id(t0):
if a < t0:
print "a/t0 comparison failed (id(a) greater)"
elif t0 < a:
print "a/t0 comparison failed"
# cml.py ends here.

BIN
tools/cml2-tools/cml.pyc Normal file

Binary file not shown.

857
tools/cml2-tools/cmladvent.py Executable file
View File

@@ -0,0 +1,857 @@
#!/usr/bin/env python
#
# cmladvent.py -- CML2 configurator adventure-game front end
# by Eric S. Raymond, <esr@thyrsus.com>
#
# This illustrates how easy it is to wrap a front end around cmlsystem.
# Purely in the interests of science, of course...
#
import sys
if sys.version[0] < '2':
print "Python 2.0 or later is required for this program."
sys.exit(0)
import os, string, getopt, cmd, time, whrandom, random
import cml, cmlsystem
# Globals
debug = 0
proflog = partialsave = None
banner = ""
gruestate = darkturns = 0
lanternloc = None
configfile = None
configuration = None
directions = ('n','e','s','w','ne','sw','se','nw','dn','up')
# User-visible strings in the configurator. Separated out in order to
# support internationalization.
_eng = {
# Strings used in the command help -- these should align
"LHELP":"look [target] -- look here or at target (direction or option).",
"NHELP":"nearby -- list nearby rooms (useful with go)",
"GHELP":"go -- go to a named menu (follow with the label).",
"IHELP":"inventory -- show which options you have picked up.",
"THELP":"take [module] -- set options, follow with option names.",
"SETHELP":"set -- set numeric or string; follow with symbol and value.",
"DHELP":"drop -- unset options, follow with option names or `all'.",
"LDHELP":"load -- read in a configuration (follow with the filename).",
"SHELP":"save -- save the configuration (follow with a filename).",
"XYZZY":"xyzzy -- toggle suppression flag.",
"QHELP":"quit -- quit, discarding changes.",
"XHELP":"exit -- exit, saving the configuration.",
# Grue/lantern messages
"BRASSOFF":"A brass lantern (unlit).",
"BRASSON":"A brass lantern (lit).",
"DARK":"It is very dark. If you continue, you are likely to be eaten by a grue.",
"EATEN":"*CHOMP*! You have been eaten by a slavering grue. Game over.",
"GLOW":"The lantern radiates a mellow golden light.",
"LANTERN":"lantern",
"LANTERNDROP":"Lantern: dropped.",
"LANTERNTAKE":"Lantern: taken.",
"LONGLANTERN":"A brass lantern is here.",
"LANTERNHELP":"""
You see a brass lantern with a ring-shaped handle, hooded and paned with
clear glass. A toggle on the lamp connects to a firestriker inside it.
On the bottom is stamped a maker's mark that reads:
Another fine product of FrobozzCo.
Made in Plumbat, Great Underground Empire
""",
# Other strings
"ABORTED":"Configurator aborted.",
"BADOPTION":"cmladvent: unknown option on command line.\n",
"BOOLEAN":"`y' and `n' can only be applied to booleans or tristates",
"CANNOTSET":" Can't assign this value for bool or trit symbol.",
"CONSTRAINTS":"Constraints:",
"DEFAULT":"Default: ",
"DERIVED":"Symbol %s is derived and cannot be set.",
"DIRHELP":"You can move in compass directions n,e,w,s,ne,nw,se,sw, up, or dn for down.",
"DONE":"Done",
"DROPPED":"%s: dropped.",
"EFFECTS":"Side effects:",
"EH?":"Eh?",
"EXIT":"Exit",
"EXITS":"Passages exit up, %s.",
"EXTRAROOMS":"Other nearby rooms are: %s.",
"GOODBYE":"You emerge, blinking, into the daylight.",
"INROOM":"In %s room.",
"INVISIBLE":"Symbol is invisible",
"ISHERE":"There is an option named %s here.",
"LOADFAIL":"Loading '%s' failed, continuing...",
"MDISABLED":"Module-valued symbols are not enabled",
"MNOTVALID":" m is not a valid value for %s",
"NEW":"(NEW)",
"NNOTVALID":" n is not a valid value for %s",
"NOANCEST":"No ancestors.",
"NOBUTTON":"I don't see button %s here.",
"NOCMDLINE":"%s is the wrong type to be set from the command line",
"NODEPS":"No dependents.",
"NODIR":"You see nothing special in that direction.",
"NOFILE":"cmlconfigure: '%s' does not exist or is unreadable.",
"NOHAVE":"You don't have %s.",
"NOHELP":"No help available for %s",
"NOHERE":"I see no `%s' here.",
"NOMATCHES":"No matches.",
"NONEXIST":"No such location.",
"NOSUCHAS":"No such thing as",
"NOTSAVED":"Configuration not saved",
"NOWAY":"You can't go in that direction from here.",
"OUTOFBOUNDS":"Legal values are in %s",
"PARAMS":" Config = %s, prefix = %s",
"PASSAGEALL":"Passages lead off in all directions.",
"PASSAGEUP":"A passage leads upwards.",
"PHELP":"press -- press a button (follow with the button name).",
"POSTMORTEM":"The ruleset was inconsistent. A state dump is in the file `post.mortem'.",
"REALLY":"Really exit without saving?",
"ROLLBACK":"%s=%s would have violated these requirements:",
"ROOMBANNER":"The %s room. A sign reads `%s'.",
"SAVEAS":"Save As...",
"SAVEEND":"Done",
"SAVESTART":"Saving %s",
"SAVING":"Saving...",
"SHOW_ANC":"Show ancestors of symbol: ",
"SHOW_DEP":"Show dependents of symbol: ",
"SIDEEFFECTS":"Side Effects",
"SIDEFROM":"Side effects from %s:",
"SUPPRESSOFF":"Suppression turned off.",
"SUPPRESSON":"Suppression turned on.",
"SYMUNKNOWN":"cmlconfigure: unknown symbol %s\n",
"TAKEN":"%s: taken.",
"TRIT":"`m' can only be applied to tristates",
"TRYPRESS":"That doesn't work. You might try pressing another button.",
"TWISTY":"You are in a maze of twisty little %s menus, all different.",
"USESET":"What? Configure %s with your bare hands?",
"VALUE":"Value of %s is %s.",
"VISIBLE":"Symbol is visible.",
"VISIBILITY":"Visibility: ",
"WALLCHOICE":"There is a row of buttons on the wall of this room. They read:",
"WALLDEFAULT":"The button marked %s is pressed.",
"WELCOME":"Welcome to CML2 Adventure, version %s.",
# General help
"GENHELP":"""Welcome to the adventure configurator. For a command summary, type `commands'.
In general, a three-letter abbreviation of any command word is sufficient
to identify it to the parser.
This interface emulates the style of classic text adventure games such as
Colossal Cave Adventure and Zork. Configuration menus are rooms, and
configuration options are objects that can be taken and dropped (except
for choice/radiobutton symbols, which become buttons on various room walls).
Objects and rooms may silently appear and disappear as visibilities
change.
Have fun, and beware of the lurking grue!
"""
}
grafitti = (
'N tensvggb ernqf: "Gur Jhzchf jnf urer. Nera\'g lbh tynq ur\'f abg urer abj?"',
'N tensvggb ernqf: "Uryyb, fnvybe!"',
'N tensvggb ernqf: "Sebqb yvirf!"',
'N tensvggb ernqf: "Guvf fcnpr sbe erag."',
'N tensvggb ernqf: "Guvf Jnl gb gur Rterff..."',
# Bofpher Pbybffny Pnir Nqiragher ersreraprf ortva urer.
'Ba bar jnyy vf n tynff-sebagrq obk ubyqvat na nkr.\aBa gur tynff vf jevggra: "OERNX TYNFF VA PNFR BS QJNEIRF"',
'N tensvggb ernqf: "Srr svr sbr sbb!',
# Bofpher Mbex ersreraprf ortva urer.
'N tensvggb ernqf: "Ragunevba gur Jvfr fyrcg urer."',
'N tensvggb ernqf: "N mbexzvq fnirq vf n mbexzvq rnearq."',
'Bar jnyy qvfcynlf n sbezny cbegenvg bs W. Cvrecbag Syngurnq.',
'Bar jnyy qvfcynlf n qhfgl cbegenvg bs gur Rzcrebe Zhzob VV.',
'Bar jnyy qvfcynlf n cvpgher bs gur terng tenabyn fzrygref bs Cyhzong.',
'Bar jnyy qvfcynlf n gnpxl oynpx-iryirg cnvagvat bs n tbyqra-sheerq zvak jvgu uhtr rlrf.',
# Bofpher Q&Q ersreraprf ortva urer
'N tensvggb ernqf: "Vg pbhyq bayl or orggre ng Pnfgyr Terlunjx"',
'N tensvggb ernqf: "Cnenylfvf vf va gur rlr bs gur orubyqre"',
# Bofpher wbxr sbe QrPnzc/Cengg snaf
'N tensvggb ernqf: "Lativ vf n ybhfr!"',
# Abg-fb-bofpher Yvahk ersreraprf ortva urer.
'Ba bar jnyy vf n cubgbtencu bs Yvahf Gbeinyqf, qevaxvat Thvaarff.',
'N jnyy oenpxrg ubyqf n qvfpneqrq cnve bs Nyna Pbk\'f fhatynffrf. Oebamrq.',
'Ba bar jnyy vf n cbegenvg bs EZF va shyy Fg. Vtahpvhf qent.',
'Ba bar jnyy vf n cvpgher bs Yneel Jnyy ubyqvat n ynetr chzcxva.',
'Ba bar jnyy vf jung nccrnef gb or n cubgbtencu bs Thvqb\'f gvzr znpuvar.',
'Gur sybbe vf yvggrerq jvgu fcrag .45 furyyf. Revp Enlzbaq zhfg unir orra urer.',
)
grafittishuffle = []
grafitticount = 0
# Eventually, do more intelligent selection using LOCALE
lang = _eng
def roll(n):
"Return a random number in the range 0..n-1."
return random.randrange(n)
def shuffle(size):
"Generate a random permutation of 0...(size - 1)."
shuffle = range(size)
for i in range(1, size+1):
j = random.randrange(i)
holder = shuffle[i - 1]
shuffle[i - 1] = shuffle[j]
shuffle[j] = holder
return shuffle
def rot13(str):
res = ""
for c in str:
if c in string.uppercase:
res += chr(ord('A') + ((ord(c)-ord('A')) + 13) % 26)
elif c in string.lowercase:
res += chr(ord('a') + ((ord(c)-ord('a')) + 13) % 26)
else:
res += c
return res
def newroom(room):
# There is a chance of grafitti
global grafitticount, grafittishuffle
if grafitticount < len(grafitti):
if not hasattr(room, "visits") and roll(3) == 0:
room.grafitti = grafitti[grafittishuffle[grafitticount]]
grafitticount += 1
# State machine for lantern and grue
global lanternloc, gruestate, darkturns
if gruestate == 0: # Initial state
if not hasattr(room, "visits") and roll(4) == 0:
gruestate += 1
lanternloc = room
elif gruestate == 1: # Lantern has been placed
if roll(4) == 0:
gruestate += 1
elif gruestate == 2: # It's dark now
darkturns += 1
if darkturns > 2 and roll(4) == 0:
print lang["EATEN"]
raise SystemExit
def visit(room, level=0):
"Visit a room, and describe at any of four verbosity levels."
# 0 = quiet, 1 = name only, 2 = name + help,
# 3 = name + help + exits, 4 = name + help + exits + contents
configuration.visit(room)
# Compute visible exits
room.exits = filter(lambda x: x.type in ("menu", "choices"), room.items)
room.exits = filter(configuration.is_visible, room.exits)
# This way of assigning directions has the defect that they may
# change as submenus become visible/invisible. Unfortunately,
# the alternative is not being able to assign directions at all
# for long menus.
room.directions = {}
for (dir,other) in zip(directions[:-1], room.exits):
room.directions[dir] = other
if level == 0:
return
elif level == 1:
print lang["INROOM"] % room.name
else:
print lang["ROOMBANNER"] % (room.name, room.prompt)
# Only display room exits at level 3 or up
if level >= 3:
if len(room.exits) > 9:
print lang["PASSAGEALL"]
elif room.exits:
print lang["EXITS"] % ", ".join(room.directions.keys())
elif room != configuration.start:
print lang["PASSAGEUP"]
print
# Display help at level 2 or up
help = room.help()
if help:
sys.stdout.write(help)
# Display grafitti at level 2 or up.
if hasattr(room, "grafitti"):
print rot13(room.grafitti) + "\n"
# Only display other contents of room at level 4 or up
if level >= 4:
if room.type == "choices":
print lang["WALLCHOICE"]
print ", ".join(map(lambda x:x.name, room.items))
print lang["WALLDEFAULT"] % room.menuvalue.name
else:
for symbol in room.items:
if symbol.is_symbol() and configuration.is_visible(symbol) and not symbol.eval():
print lang["ISHERE"] % symbol.name
# Some things are always shown
if lanternloc == room:
print lang["LONGLANTERN"]
if gruestate == 2:
print lang["DARK"]
def inventory():
# Write mutable symbols, including defaulted modular symbols.
configuration.module_suppress = 0
if lanternloc == 'user':
if gruestate == 3:
print lang["BRASSON"]
else:
print lang["BRASSOFF"]
__inventory_recurse(configuration.start)
if configuration.trit_tie:
configuration.module_suppress = (configuration.trit_tie.eval() == cml.m)
# Write all derived symbols
#config_sh.write(configuration.lang["SHDERIVED"])
#for entry in configuration.dictionary.values():
# if entry.is_derived():
# __inventory_recurse(entry, config_sh)
def __inventory_recurse(node):
if not configuration.saveable(node):
return
elif node.items:
for child in node.items:
__inventory_recurse(child)
elif node.type != 'message':
symname = configuration.prefix + node.name
value = node.eval(configuration.debug)
if not value or not node.setcount:
return
try:
if node.type == "decimal":
sys.stdout.write("%s=%d\n" % (symname, value))
elif node.type == "hexadecimal":
sys.stdout.write("%s=0x%x\n" % (symname, value))
elif node.type == "string":
sys.stdout.write("%s=\"%s\"\n" % (symname, value))
elif node.type in ("bool", "trit"):
sys.stdout.write("%s=%s\n" % (symname, `value`))
except:
(errtype, errval, errtrace) = sys.exc_info()
print "Internal error %s while writing %s." % (errtype, node)
raise SystemExit, 1
class advent_menu(cmd.Cmd):
"Adventure-game interface class."
def set_symbol(self, symbol, value, freeze=0):
"Set the value of a symbol -- line-oriented error messages."
if symbol.is_numeric() and symbol.range:
if not configuration.range_check(symbol, value):
print lang["OUTOFBOUNDS"] % (symbol.range,)
return 0
(ok, effects, violations) = configuration.set_symbol(symbol, value, freeze)
if effects:
print lang["EFFECTS"]
sys.stdout.write(string.join(effects, "\n") + "\n\n")
if not ok:
print lang["ROLLBACK"] % (symbol.name, value)
sys.stdout.write(string.join(violations, "\n") + "\n")
return ok
def __init__(self, myconfigfile=None, mybanner=""):
cmd.Cmd.__init__(self)
self.configfile = myconfigfile
if mybanner and configuration.banner.find("%s") > -1:
self.banner = configuration.banner % mybanner
elif banner:
self.banner = mybanner
else:
self.banner = configuration.banner
self.current = configuration.start;
self.prompt = "> "
print lang["TWISTY"]%(configuration.banner,)
self.last = None
visit(configuration.start, 4)
def do_look(self, line):
if not line: # Look at where we are
visit(self.current, 4)
elif line == "up": # Look up
if self.current == configuration.start:
print lang["NODIR"]
else:
visit(self.current.menu, 2)
elif line in directions: # Look in a direction
if line in self.current.directions.keys():
visit(self.current.directions[line], 2)
else:
print lang["NODIR"]
# Look at an option
elif line in map(lambda x: x.name, filter(lambda x: x.is_logical(), self.current.items)):
symbol = configuration.dictionary[line]
print lang["VALUE"] % (line, symbol.eval())
help = symbol.help()
if help:
sys.stdout.write(help)
else:
print lang["NOHERE"] % line
do_loo = do_look
def do_nearby(self, dummy):
if self.current != configuration.start:
print lang["ROOMBANNER"] % (self.current.menu.name, self.current.menu.prompt)
for (dir, symbol) in self.current.directions.items():
if symbol.type in ("menu", "choices") and configuration.is_visible(symbol):
print ("%-2s: " % dir) + lang["ROOMBANNER"] % (symbol.name, symbol.prompt)
if len(self.current.exits) > len(directions):
print lang["EXTRAROOMS"] % ", ".join(map(lambda x: x.name, self.current.exits[9:]))
print
do_nea = do_nearby
def do_go(self, symname):
if not symname:
print lang["EH?"]
return
symbol = configuration.dictionary.get(symname)
if symbol and symbol.type in ("menu", "choices"):
self.current = symbol
if not configuration.is_visible(self.current) and not self.current.frozen():
print lang["SUPPRESSOFF"]
self.suppressions = 0
else:
print lang["NONEXIST"]
def do_dir(self, dir):
to = self.current.directions.get(dir)
if to:
self.current = to
else:
print lang["NOWAY"]
def do_n(self, dummy): self.do_dir('n')
def do_e(self, dummy): self.do_dir('e')
def do_w(self, dummy): self.do_dir('w')
def do_s(self, dummy): self.do_dir('s')
def do_ne(self, dummy): self.do_dir('ne')
def do_nw(self, dummy): self.do_dir('nw')
def do_se(self, dummy): self.do_dir('se')
def do_sw(self, dummy): self.do_dir('sw')
def do_u(self, dummy): self.do_up(dummy)
def do_d(self, dummy): self.do_dir('dn')
def do_up(self, dummy):
if self.current == configuration.start:
print lang["GOODBYE"]
raise SystemExit
else:
self.current = self.current.menu
def do_inventory(self, dummy):
inventory()
do_inv = do_inventory
do_i = do_inventory
def do_drop(self, line):
global lanternloc, gruestate
if not line:
print lang["EH?"]
return
words = line.lower().split()
if words == ["all"] and self.current.type != "choices":
words = map(lambda x:x.name, filter(lambda x:x.is_logical() and configuration.is_visible(x) and not x.eval(), self.current.items))
if lanternloc == 'user':
words.append(lang["LANTERN"])
for thing in words:
if thing == lang["LANTERN"]:
lanternloc = self.current
gruestate = 1
print lang["LANTERNDROP"]
else:
symbolname = thing.upper()
symbol = configuration.dictionary.get(symbolname)
if not symbol:
print lang["NOSUCHAS"], symbolname
continue
elif not symbol.eval():
print lang["NOHAVE"] % symbolname
continue
elif symbol.menu.type == "choices":
if symbol.menu != self.current:
print lang["NOBUTTON"] % symbolname
else:
print lang["TRYPRESS"]
return
elif symbol.is_logical():
ok = self.set_symbol(symbol, cml.n)
elif symbol.is_numeric():
ok = self.set_symbol(symbol, 0)
elif symbol.type == "string":
ok = self.set_symbol(symbol, "")
if ok:
print lang["DROPPED"] % symbol.name
do_dro = do_drop
def do_take(self, line):
global lanternloc
if not line:
print lang["EH?"]
return
words = line.lower().split()
if words == ["all"] and self.current.type != "choices":
words = map(lambda x:x.name, filter(lambda x:x.is_logical() and configuration.is_visible(x) and not x.eval(), self.current.items))
if lanternloc == self.current:
words.append(lang["LANTERN"])
if ("module" in words):
tritval = cml.m
words.remove("module")
else:
tritval = cml.y
for thing in words:
if thing == lang["LANTERN"]:
lanternloc = 'user'
print lang["LANTERNTAKE"]
else:
symbolname = thing.upper()
symbol = configuration.dictionary.get(symbolname)
if not symbol:
print lang["NOSUCHAS"], symbolname
elif symbol.menu != self.current:
print lang["NOHERE"] % symbol.name
elif symbol.is_logical():
if self.set_symbol(symbol, tritval):
print lang["TAKEN"] % symbol.name
else:
print lang["USESET"] % symbol.name
do_tak = do_take
def do_press(self, line):
if not line:
print lang["EH?"]
else:
symbol = configuration.dictionary.get(line)
if not symbol or symbol.menu != self.current:
print lang["NOHERE"] % line
else:
self.set_symbol(symbol, cml.y)
do_pus = do_push = do_pre = do_press
def do_light(self, dummy):
global gruestate
if lanternloc == 'user':
print lang["GLOW"]
gruestate = 3
else:
print lang["NOHERE"] % lang["LANTERN"]
do_lig = do_light
def do_set(self, line):
symbol = None
try:
(symname, value) = line.split()
symbol = configuration.dictionary[symname]
except:
print lang["EH?"]
if not symbol:
print lang["NOSUCHAS"], symbol.name
elif symbol.menu != self.current:
print lang["NOHERE"] % symbol.name
elif symbol.menu.type == "choices" or symbol.is_logical():
print lang["CANTDO"]
elif symbol.is_numeric():
self.set_symbol(symbol, int(value))
elif symbol.type == "string":
self.set_symbol(symbol, value)
def do_xyzzy(self, dummy):
# Toggle the suppressions flag
configuration.suppressions = not configuration.suppressions
if configuration.suppressions:
print lang["SUPPRESSON"]
else:
print lang["SUPPRESSOFF"]
return 0
def do_load(self, line):
if not line:
print lang["EH?"]
return
file = string.strip(line)
if file.find(' ') > -1:
(file, option) = file.split(' ')
try:
(changes, errors) = configuration.load(file, freeze=(option == "frozen"))
except IOError:
print lang["LOADFAIL"] % file
else:
if errors:
print errors
print lang["INCCHANGES"] % (changes,file)
if configuration.side_effects:
sys.stdout.write(string.join(configuration.side_effects, "\n") + "\n")
do_loa = do_load
def do_save(self, line):
if not line:
print lang["EH?"]
return
file = string.strip(line)
failure = configuration.save(file, cml.Baton(lang["SAVESTART"] % file, lang["SAVEEND"]))
if failure:
print failure
do_sav = do_save
def do_exit(self, dummy):
# Terminate this cmd instance, saving configuration
self.do_s(configfile)
return 1
do_exi = do_exit
def do_quit(self, line):
# Terminate this cmd instance, not saving configuration
return 1
do_qui = do_quit
# Debugging commands -- not documented
def do_verbose(self, line):
# Set the debug flag
if not line:
configuration.debug += 1
else:
configuration.debug = int(line)
return 0
do_ver = do_verbose
def do_examine(self, line):
# Examine the state of a given symbol
symbol = string.strip(line)
if configuration.dictionary.has_key(symbol):
entry = configuration.dictionary[symbol]
print entry
if entry.constraints:
print lang["CONSTRAINTS"]
for wff in entry.constraints:
print cml.display_expression(wff)
if configuration.is_visible(entry):
print lang["VISIBLE"]
else:
print lang["INVISIBLE"]
help = entry.help()
if help:
print help
else:
print lang["NOHELP"] % (entry.name,)
elif symbol == "lantern":
if lanternloc == "user" or lanternloc == self.current:
print lang["LANTERNHELP"]
else:
print lang["NOHERE"] % lang["LANTERN"]
else:
print lang["NOSUCHAS"], symbol
return 0
do_exa = do_examine
def emptyline(self):
return 0
def do_commands(self, dummy):
print string.join(map(lambda x: lang[x],
("LHELP", "NHELP", "GHELP", "IHELP",
"DHELP", "THELP", "PHELP", "SETHELP",
"LDHELP", "SHELP", "XYZZY",
"QHELP", "XHELP", "DIRHELP")),
"\n")
def help_look(self):
print lang["LHELP"]
help_loo = help_look
def help_nearby(self):
print lang["NHELP"]
help_nea = help_nearby
def help_go(self):
print lang["GHELP"]
def help_inventory(self):
print lang["IHELP"]
help_inv = help_inventory
def help_drop(self):
print lang["DHELP"]
help_dro = help_drop
def help_take(self):
print lang["THELP"]
help_tak = help_take
def help_press(self):
print lang["PHELP"]
help_pus = help_push = help_pre = help_press
def help_set(self):
print lang["SETHELP"]
def help_xyzzy(self):
print lang["XYZZY"]
def help_load(self):
print lang["LDHELP"]
help_loa = help_load
def help_save(self):
print lang["SHELP"]
help_sav = help_save
def help_quit(self):
print lang["QHELP"]
help_qui = help_quit
def help_exit(self):
print lang["XHELP"]
help_exi = help_exit
def do_help(self, dummy):
print lang["GENHELP"]
def postcmd(self, stop, dummy):
if stop:
return stop
if self.current != self.last:
newroom(self.current)
visit(self.current, 4 - 3 * (self.current.visits > 1))
self.last = self.current
return None
# Rulebase loading and option processing
def load_system(cmd_options, cmd_arguments):
"Read in the rulebase and handle command-line arguments."
global debug, configfile, configuration
debug = 0;
configfile = None
if not cmd_arguments:
rulebase = "rules.out"
else:
rulebase = cmd_arguments[0]
try:
open(rulebase, 'rb')
except IOError:
print lang["NOFILE"] % (rulebase,)
raise SystemExit
configuration = cmlsystem.CMLSystem(rulebase)
process_options(configuration, cmd_options)
configuration.debug_emit(1, lang["PARAMS"] % (configfile,configuration.prefix))
# Perhaps the user needs modules enabled initially
if configuration.trit_tie and cml.evaluate(configuration.trit_tie):
configuration.trits_enabled = 1
# Don't count all these automatically generated settings
# for purposes of figuring out whether we should confirm a quit.
configuration.commits = 0
return configuration
def process_include(myconfiguration, file, freeze):
"Process a -i or -I inclusion option."
# Failure to find an include file is non-fatal
try:
(changes, errors) = myconfiguration.load(file, freeze)
except IOError:
print lang["LOADFAIL"] % file
return
if errors:
print errors
elif myconfiguration.side_effects:
print lang["SIDEFROM"] % file
sys.stdout.write(string.join(myconfiguration.side_effects, "\n") + "\n")
def process_define(myconfiguration, val, freeze):
"Process a -d=xxx or -D=xxx option."
parts = string.split(val, "=")
sym = parts[0]
if myconfiguration.dictionary.has_key(sym):
sym = myconfiguration.dictionary[sym]
else:
myconfiguration.errout.write(lang["SYMUNKNOWN"] % (`sym`,))
sys.exit(1)
if sym.is_derived():
myconfiguration.debug_emit(1, lang["DERIVED"] % (`sym`,))
sys.exit(1)
elif sym.is_logical():
if len(parts) == 1:
val = 'y'
elif parts[1] == 'y':
val = 'y'
elif parts[1] == 'm':
myconfiguration.trits_enabled = 1
val = 'm'
elif parts[1] == 'n':
val = 'n'
elif len(parts) == 1:
print lang["NOCMDLINE"] % (`sym`,)
sys.exit(1)
else:
val = parts[1]
(ok, effects, violations) = myconfiguration.set_symbol(sym,
myconfiguration.value_from_string(sym, val),
freeze)
if effects:
print lang["EFFECTS"]
sys.stdout.write(string.join(effects, "\n") + "\n\n")
if not ok:
print lang["ROLLBACK"] % (sym.name, val)
sys.stdout.write(string.join(violations,"\n")+"\n")
def process_options(myconfiguration, options):
# Process command-line options second so they override
global list, configfile, debug, banner
configfile = "config.out"
for (switch, val) in options:
if switch == '-B':
banner = val
elif switch == '-d':
process_define(myconfiguration, val, freeze=0)
elif switch == '-D':
process_define(myconfiguration, val, freeze=1)
elif switch == '-i':
process_include(myconfiguration, val, freeze=0)
elif switch == '-I':
process_include(myconfiguration, val, freeze=1)
elif switch == '-l':
list = 1
elif switch == '-o':
configfile = val
elif switch == '-v':
debug = debug + 1
myconfiguration.debug = myconfiguration.debug + 1
elif switch == '-S':
myconfiguration.suppressions = 0
# Main sequence -- isolated here so we can profile it
def main(options, arguments):
global configuration
try:
myconfiguration = load_system(options, arguments)
except KeyboardInterrupt:
raise SystemExit
# Set seed for random-number functions
whrandom.seed(int(time.time()) % 256, os.getpid() % 256, 23)
global grafittishuffle
grafittishuffle = shuffle(len(grafitti))
print lang["WELCOME"] % cml.version
myconfiguration.errout = sys.stdout
advent_menu(configfile, banner).cmdloop()
if __name__ == '__main__':
try:
runopts = "aB:cD:d:h:i:I:lo:P:R:StVvWx"
(options,arguments) = getopt.getopt(sys.argv[1:], runopts)
if os.environ.has_key("CML2OPTIONS"):
(envopts, envargs) = getopt.getopt(
os.environ["CML2OPTIONS"].split(),
runopts)
options = envopts + options
except:
print lang["BADOPTION"]
sys.exit(1)
for (switch, val) in options:
if switch == "-V":
print "cmladvent", cml.version
raise SystemExit
elif switch == '-P':
proflog = val
try:
import readline
except:
pass
try:
if proflog:
import profile, pstats
profile.run("main(options, arguments)", proflog)
else:
main(options, arguments)
except KeyboardInterrupt:
#if configuration.commits > 0:
# print lang["NOTSAVED"]
print lang["ABORTED"]
except "UNSATISFIABLE":
#configuration.save("post.mortem")
print lang["POSTMORTEM"]
raise SystemExit, 1
# That's all, folks!

1327
tools/cml2-tools/cmlcompile.py Executable file

File diff suppressed because it is too large Load Diff

3323
tools/cml2-tools/cmlconfigure.py Executable file

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

122
tools/cml2-tools/configtrans.py Executable file
View File

@@ -0,0 +1,122 @@
#!/usr/bin/env python
"""
configtrans.py -- translate between CML1 and CML2 config formats.
This handles the impedance mismatch between CML2's explicit NAME=VALUE
output format and the formats expected by the Linux build machinery.
Note: it also makes backups whenever it touches a file.
configtrans.py -h includeout -s configout cml2file
configtrans.py -t <newconfig >oldconfig
"""
import sys, os, getopt, re
def linetrans(hook, instream, outstream, trailer=None):
"Line-by-line translation between streams."
if not hasattr(instream, "readline"):
instream = open(instream, "r")
if not hasattr(outstream, "readline"):
outstream = open(outstream, "w")
while 1:
line = instream.readline()
if not line:
break
new = hook(line)
if new:
outstream.write(new)
instream.close()
if trailer:
outstream.write(trailer)
outstream.close()
def write_include(line):
"Transform a SYMBOL=VALUE line to CML1 include format."
if line.find("PRIVATE") > -1 or line[:2] == "$$":
return ""
match = isnotset.match(line)
if match:
return "#undef %s\n" % match.group(1)
if line == "#\n":
return None
elif line[0] == "#":
return "/* " + line[1:].strip() + " */\n"
eq = line.find("=")
if eq == -1:
return line
else:
line = line.split('#')[0]
symbol = line[:eq]
value = line[eq+1 :].strip()
if value == 'y':
return "#define %s 1\n" % symbol
elif value == 'm':
return "#undef %s\n#define %s_MODULE 1\n" % (symbol, symbol)
elif value == 'n':
return "#undef %s\n" % symbol
else:
return "#define %s %s\n" % (symbol, value)
def write_defconfig(line):
"Transform a SYMBOL=VALUE line to CML1 defconfig format."
if line[:2] == "$$":
return ""
eq = line.find("=")
if eq == -1:
return line
else:
line = line.split('#')[0]
line = line.strip()
if len(line) == 0 or line[-1] != "\n":
line += "\n"
symbol = line[:eq]
value = line[eq+1:].strip()
if value == 'n':
return "# %s is not set\n" % symbol
else:
return line
def revert(line):
"Translate a CML1 defconfig file to CML2 format."
match = isnotset.match(line)
if match:
return "%s=n\n" % match.group(1)
else:
return line
if __name__ == '__main__':
isnotset = re.compile("^# (.*) is not set")
include = defconfig = translate = None
(options, arguments) = getopt.getopt(sys.argv[1:], "h:s:t")
for (switch, val) in options:
if switch == '-h':
includefile = val
try:
os.rename(val, val + ".old")
except OSError:
pass
elif switch == '-s':
defconfig = val
try:
os.rename(val, val + ".old")
except OSError:
pass
elif switch == '-t':
translate = 1
if len(arguments) > 0:
try:
if includefile:
linetrans(write_include, arguments[0], includefile, "#define AUTOCONF_INCLUDED\n")
if defconfig:
linetrans(write_defconfig, arguments[0], defconfig)
except IOError, args:
sys.stderr.write("configtrans: " + args[1] + "\n");
raise SystemExit, 1
elif translate:
linetrans(revert, sys.stdin, sys.stdout)
else:
print "usage: configtrans.py -t [-h includefile] [-s defconfig] file"
raise SystemExit, 1
# That's all, folks!

267
tools/cml2-tools/helpmerge.py Executable file
View File

@@ -0,0 +1,267 @@
#!/usr/bin/env python
#
# Merge a Configure.help file into a file of CML2 symbol declarations
#
# The Configure.help file must be argument 1; the partial symbol file
# must be argument 2.
#
# When given the -c option, suppress normal output and instead
# consistency-check the prompts.
import sys, string, re, os, os.path
if sys.version[0] < '2':
print "Python 2.0 or later is required for this program."
sys.exit(0)
directory = ""
def extract_dir(line, splitlocs):
global directory
# Handle directory directive
if line[:14] == "#% Directory: ":
fields = line[14:].strip().split()
if len(fields) == 1:
directory = fields[0]
else:
splitlocs[fields[0]] = fields[2]
return 1
else:
return 0
def help_scan(file, prefix):
# This assumes the format of Axel Boldt's Configure.help file
global directory
dict = {}
splitlocs = {}
stream = open(file)
name = None
ringbuffer = [0, 0, 0, 0, 0]
ringindex = choiceflag = 0
prompt = ""
lastline = ""
start = 0
while 1:
line = stream.readline()
if extract_dir(line, splitlocs):
continue
# Now everything else
if line and line[0] == '#':
if line.find("Choice:") > -1:
choiceflag = 1
continue
ringbuffer[ringindex] = here = stream.tell()
ringindex = (ringindex + 1) % 5
if line and line[0] in string.whitespace:
continue
if not line or line[0:7] == prefix:
if name:
if dict.has_key(name):
sys.stderr.write("Duplicate help text for %s\n" % name)
dict[name] = (file, start, ringbuffer[(ringindex - 4) % 5], prompt)
if directory != "UNKNOWN":
splitlocs[name] = directory
directory = "UNKNOWN"
if line:
name = string.strip(line[7:])
start = here
if choiceflag:
prompt = None # Disable prompt checking
else:
prompt = lastline.strip()
choiceflag = 0
else:
break
lastline = line
stream.close()
return (dict, splitlocs)
def fetch_help(symbol, helpdict):
"Fetch help text associated with given symbol, if any."
if helpdict.has_key(symbol):
(file, start, end, prompt) = helpdict[symbol]
stream = open(file)
stream.seek(start)
help = stream.read(end - start)
# Canonicalize trailing whitespace
help = help.rstrip() + "\n"
stream.close()
return help
else:
return None
def merge(helpfile, templatefile):
"Merge a Configure.help with a symbols file, write to stdout."
(helpdict, splitlocs) = help_scan(helpfile, "CONFIG_")
template = open(templatefile, "r")
promptre = re.compile("(?<=['\"])[^'\"]*(?=['\"])")
os.system('rm -f `find kernel-tree -name "*symbols.cml"`')
trim = re.compile("^ ", re.M)
trailing_comment = re.compile("\s*#[^#']*$")
outfp = None
lineno = 0
while 1:
lineno += 1
line = template.readline()
if not line:
break
elif line == "\n":
continue
elif line[0] == "#":
extract_dir(line, splitlocs)
continue
# Sanity check
prompt = promptre.search(line)
if not prompt:
sys.stderr.write("Malformed line %s: %s" % (lineno, line))
raise SystemExit, 1
# We've hit something that ought to be a symbol line
fields = line.split()
symbol = fields[0]
template_has_text = line.find("text\n") > -1
if symbol[:7] == "CONFIG_":
symbol = symbol[7:]
if checkonly:
# Consistency-check the prompts
prompt = prompt.group(0)
if helpdict.has_key(symbol):
oldprompt = helpdict[symbol][3]
if oldprompt == None:
continue
if oldprompt[-15:] == " (EXPERIMENTAL)":
oldprompt = oldprompt[:-15]
if oldprompt[-11:] == " (OBSOLETE)":
oldprompt = oldprompt[:-11]
if oldprompt[-12:] == " (DANGEROUS)":
oldprompt = oldprompt[:-12]
if oldprompt != prompt:
sys.stdout.write("%s:\n" % (symbol,))
sys.stdout.write("CML1: '" + oldprompt + "'\n")
sys.stdout.write("CML2: '" + prompt + "'\n")
while 1:
line = template.readline()
if line == ".\n":
break
else:
# Now splice in the actual help text
helptext = fetch_help(symbol, helpdict)
if helptext and template_has_text:
print line
sys.stderr.write("Template already contains help text for %s!\n" % symbol)
raise SystemExit, 1
if outfp:
outfp.close()
if splitlocs.has_key(symbol):
dest = splitlocs[symbol]
else:
dest = directory
if dest == "UNKNOWN":
sys.stderr.write("No directory for %s\n" % symbol)
sys.exit(1)
#print "%s -> %s" % (symbol, dest)
dest = os.path.join("kernel-tree", dest[1:], "symbols.cml")
exists = os.path.exists(dest)
if exists:
outfp = open(dest, "a")
else:
outfp = open(dest, "w")
outfp.write("symbols\n")
if helptext:
leader = line.rstrip()
comment_match = trailing_comment.search(leader)
if comment_match:
comment = comment_match.group(0)
leader = leader[:comment_match.start(0)]
else:
comment = ""
if len(leader) < 68:
outfp.write(leader + "\ttext")
if comment:
outfp.write("\t" + comment)
outfp.write("\n")
else:
outfp.write(leader + comment + "\ntext\n")
outfp.write(trim.sub("", helptext) + ".\n")
elif template_has_text:
outfp.write(line)
while 1:
line = template.readline()
outfp.write(line)
if line == ".\n":
break
else:
outfp.write(line)
def conditionalize(file, optset):
"Handle conditional inclusions and drop out choice lines."
import re
cond = re.compile(r"^#% (\S*) only$")
infp = open(file)
if optset:
sys.stdout.write("## This version generated for " + " with ".join(optset) + "\n")
while 1:
import re
line = infp.readline()
if not line:
break
if line[:9] == "# Choice:":
continue
match = cond.match(line)
if match and match.group(1) not in optset:
while 1:
line = infp.readline()
if not line:
break
if line == "\n":
line = infp.readline()
break
if line[:2] == "#%": # Drop out other directives
continue
sys.stdout.write(line)
def dump_symbol(symbol, helpdict):
"Dump a help entry."
sys.stdout.write("%s\n" % helpdict[symbol][3])
sys.stdout.write("CONFIG_%s\n" % symbol)
sys.stdout.write(fetch_help(symbol, helpdict))
sys.stdout.write("\n")
if __name__ == "__main__":
import getopt
checkonly = sort = 0
optset = []
(options, arguments) = getopt.getopt(sys.argv[1:], "D:Ecns")
for (switch, val) in options:
if switch == "-D":
optset.append(val)
elif switch == '-E': # Process conditionals
conditionalize(arguments[0], optset)
sys.exit(0)
elif switch == '-c': # Consistency check
checkonly = 1
elif switch == '-n': # List symbols with no match in second arg
import cmlsystem
configuration = cmlsystem.CMLSystem(arguments[1])
helpdict = help_scan(arguments[0], "CONFIG_")
keys = helpdict.keys()
keys.sort()
for symbol in keys:
if not configuration.dictionary.get(symbol):
dump_symbol(symbol, helpdict)
sys.exit(0)
elif switch == '-s': # Emit sorted version
helpdict = help_scan(arguments[0], "CONFIG_")
keys = helpdict.keys()
keys.sort()
for symbol in keys:
dump_symbol(symbol, helpdict)
sys.exit(0)
help = arguments[0]
symbols = arguments[1]
merge(help, symbols)
# That's all, folks!

764
tools/cml2-tools/kxref.py Executable file
View File

@@ -0,0 +1,764 @@
#!/usr/bin/env python
"""
kxref.py -- generate configuration symbol cross-reference for the kernel tree
This is a report generator intended to catch problems and inconsistencies
in the configuration-symbol namespace. It uses information generated by
the CML2 compiler -- notably, it relies on the compiler's scanning of
help files.
All this does is generate cross-reference reports on configuration
symbols. But they can be filtered and presented in various
interesting ways. Basic usage is like this:
kxref.py [-f filter | -h] [-l] [-x symbol] [-n re] [sourcetree]
You can set a filter using a boolean-expression minilanguage. The predicates
available are as follows:
c -- select all symbols present in code (.c, .h, .S files)
m -- select all symbols present in makefiles
n -- select all symbols defined in CML2 rulesfiles
h -- select all symbols for which help is available (CMl1 convention)
H -- select all symbols for which help is available (CML2 convention)
d -- select all symbols that occur in defconfigs
x -- select all symbols that are derived in CML2.
o -- select all symbols present in CML1 configuration files
a -- select all symbols declared in CML1 configuration files
p -- select all symbols for which autoconfigure.py has a probe
D(name) -- select all symbols transitively dependent on name
A(name) -- select all symbols transitively ancestral to name
T(type) -- select type (trit, bool, string, decimal, hexadecimal)
P(property) -- select all symbols with given property
V(symbol) -- select all symbols with given symbol in their
visibility guard.
Operations available are as follows:
& -- and (set intersection)
| -- or (set intersection)
~ -- not (set complement).
You may use parentheses for expression grouping.
This program caches a cross-reference database in a file named
xref.out, so all reports after the first are generated really fast.
You should remove this file whenever you apply a patch.
The -i option inverts the report so it's keyed by file, rather than
by symbol.
The -g option generates a patch removing file lines containing the
reported (presumably orphaned) symbols. Use with caution...it's
really only safe for hacking defconfigs.
The -x option is for debugging. It generates a report on an individual
symbol specified as an argument to the option. Flag letters are as
above, with f= giving the value of the computed filter predicate.
The -h option checks for duplicate or superfluous file inclusions
in the source tree.
The -l switch suppresses printing printing of cross-references;
only symbols matching the given filter(s) are listed.
The -n suppresses listing of files with names matching the given regexp.
If all the files a symbol occurs in are excluded, it will be omitted
from the listings.
The -t option produces a listing of symbols which either have
inconsistent CML1 types or types that differ between CML1 and CML2.
The -k option accepts a file of kill-list symbols to be ignored.
The program has some knowledge of file syntax. It ignores the
contents of comments in C, CML1, and CML2 files (e.g. does not
cross-reference symbols in such comments).
Some interesting reports:
n&~p&~a -- identifies CML2 symbols no longer declared or defined in CML1
"""
import sys, os, re, getopt, cPickle, cml, cmlsystem
xrefs = None
rulebase = None
typefind = choicere = configre = definere = mycml1types = None
def suffix(haystack, *needle):
"Does a filename have any of the given suffixes?"
for suf in needle:
if haystack[-len(suf):] == suf:
return 1
return 0
def prefix(haystack, *needle):
"Does a filename have any of the given prefixes?"
for pre in needle:
if haystack[len(pre):] == pre:
return 1
return 0
# Code for recognizing symbols and stripping out comments
# It's OK that this matches _MODULE symbols, we'll filter those out later.
configpref = re.compile("(?<![A-Z0-9_])(CONFIG_[a-zA-Z0-9_][a-zA-Z0-9_]+)")
# Regular expressions for stripping out C comments. We're aided here by the
# fact that we don't care about the contents of most of the file. So by
# first stripping out / and characters that are not part of comment
# delimiter pairs, we can make detecting comments pretty trivial. This won't
# completely strip comments of the form /* aaaa /* bbbb */, but for this
# application that's OK -- we don't have to be perfect, just reduce the
# exception cases to the point where eyeball checking is feasible. Use
# of lookaheads and lookbehinds avoids nipping off anything that might
# be a nearby bit of symbol.
#
randomslash = re.compile("(?<=[^*])/(?=[^*])")
randomstar = re.compile("(?<=[^/])\*(?=[^/])")
c_comment = re.compile("/\*[^*]*\*/")
def c_comment_strip(str):
str = randomslash.sub("", str,)
str = randomstar.sub("", str)
return c_comment.sub("", str)
# Shell, config-file, and Makefile-style comments.
#
hashcomment = re.compile("#.*\n", re.MULTILINE)
def hash_comment_strip(str):
return hashcomment.sub("", str)
# Code for generating the cross-reference
def ignore(file):
"Return 1 if the file should be ignored for cross-referencing purposes."
# Ignore CML files because we look symbols up directly in the rulebase.
return suffix(file, ".bak", ".orig", ".rej", ".cml", ".o", ".a", ".out", "log", "Log", ",v", "~")
# These are used in the language documentation
kill_list = {"CHEER":1, "BOOM":1, "BOGUS":1}
def makexref(tree):
"Generate a cross-reference dictionary for the given source tree."
global typefind, choicere, configre, definere, mycml1types
typefind = re.compile(r"(?<!define_)(bool|tristate|int|hex|string)\s+'.*'\s+CONFIG_(\w+)")
choicere = re.compile(r"^\s*choice")
configre = re.compile(rulebase.prefix + r"(\w*)")
definere = re.compile(r"^\s+define_([a-z]*)\s+(\w*)")
mycml1types = {}
def xrefvisit(dict, dir, files):
"Visit a directory on behalf of the cross-referencer."
def filevisitor(dict, file):
"Visit a file on behalf of the cross-referencer."
if file[0] == '.':
return
fp = open(file)
contents = fp.read()
fp.close()
if suffix(file, ".c", ".h", ".S"):
contents = c_comment_strip(contents)
elif suffix(file, ".in", ".cml"):
contents = hash_comment_strip(contents)
for match in configpref.findall(contents):
if suffix(match, "_MODULE"):
continue
match = namestrip(match)
if kill_list.has_key(match):
continue
elif not dict.has_key(match):
dict[match] = []
if file not in dict[match]:
dict[match].append(file)
# Parse file contents for choice symbols
if suffix(file, ".in"):
lines = contents.split("\n")
while lines:
if not choicere.match(lines[0]):
# First extract type info for ordinary symbols
m = typefind.search(lines[0])
if m:
symtype = m.group(1)
symname = m.group(2)
if not mycml1types.has_key(symname):
mycml1types[symname] = []
if (symtype, file) not in mycml1types[symname]:
mycml1types[symname].append((symtype, file))
# CML1 defines count with other symbols of their type
symdef = definere.search(lines[0])
if symdef:
symbol = namestrip(symdef.group(2))
type = symdef.group(1)
if not mycml1types.has_key(symbol):
mycml1types[symbol] = []
if (type, file) not in mycml1types[symbol]:
mycml1types[symbol].append((type, file))
lines.pop(0)
continue
else:
lines.pop(0)
while lines[0].find(rulebase.prefix) > -1:
findit = configre.search(lines[0])
symbol = namestrip(findit.group(0))
if not mycml1types.has_key(symbol):
mycml1types[symbol] = []
mycml1types[symbol].append(("choice", file))
if lines[0].find('" ') > -1:
break
lines.pop(0)
for file in files:
node = os.path.join(dir, file)[2:]
if os.path.isfile(node) and not ignore(node):
filevisitor(dict, node)
xrefdict = {}
here = os.getcwd()
os.chdir(sourcetree)
os.path.walk(".", xrefvisit, xrefdict)
os.chdir(here)
# Data reduction -- collapse CML1 cross references of identical type
for (key, value) in mycml1types.items():
if len(value) <= 1:
continue # Only interested in the multiples
else:
tdict = {}
for (type, file) in value:
tdict[type] = []
for (type, file) in value:
tdict[type].append(file)
reslist = []
for type in tdict.keys():
reslist.append((type, tdict[type]))
mycml1types[key] = reslist
# Second stage of data reduction -- if a symbol has both a choice
# declaration and another of a different type, suppress the non-choice
# declaration -- we can assume it came from a CML1 define.
for (key, value) in mycml1types.items():
if "choice" in map(lambda x: x[0], value):
mycml1types[key]=filter(lambda x: x[0]=="choice", mycml1types[key])
return (xrefdict, mycml1types)
probe_table = {}
def load_probe_table():
"Build a table of symbols for qhich we have probes."
from autoconfigure import get_arch
(ARCH, ARCHSYMBOL) = get_arch()
TRUE = 1
FALSE = 0
PRESENT = 1
ABSENT = 0
y = m = n = 0
def DEBUG(str):
pass
def PCI(prefix, symbol):
probe_table[symbol] = 1
def PCI_CLASS(match, symbol):
probe_table[symbol] = 1
def PNP(match, symbol):
probe_table[symbol] = 1
def MCA(match, symbol):
probe_table[symbol] = 1
def USBP(match, symbol):
probe_table[symbol] = 1
def USBC(match, symbol):
probe_table[symbol] = 1
def USBI(match, symbol):
probe_table[symbol] = 1
def FS(match, symbol):
probe_table[symbol] = 1
def DEV(match, symbol):
probe_table[symbol] = 1
def DEVM(match, symbol):
probe_table[symbol] = 1
def CONS(match, symbol):
probe_table[symbol] = 1
def DMESG(match, symbol, truthval=None):
probe_table[symbol] = 1
def NET(match, symbol):
probe_table[symbol] = 1
def IDE(match, symbol):
probe_table[symbol] = 1
def REQ(match, symbol):
probe_table[symbol] = 1
def CPUTYPE(match, symbol):
probe_table[symbol] = 1
def CPUINFO(match, symbol, present=None, truthval=None):
probe_table[symbol] = 1
def EXISTS(procfile, symbol):
probe_table[symbol] = 1
def MODULE(name, symbol):
probe_table[symbol] = 1
def GREP(pattern, file, symbol):
probe_table[symbol] = 1
execfile(rulesfile)
# Predicates for filtering the reports
def namestrip(name):
if rulebase.prefix and name[:len(rulebase.prefix)] == rulebase.prefix:
return name[len(rulebase.prefix):]
else:
return name
def in_code(name):
"Does a name occur in code?"
if not xrefs.has_key(name):
return 0
for file in xrefs[name]:
if suffix(file, ".c", ".S") or (suffix(file, ".h") and not suffix(file, "autoconf.h")):
return 1
return 0
def in_help(name):
"Is there help for a symbol (CML1 convention)?"
# Catch choice names that aren't in Configure.help directly.
entry = rulebase.dictionary.get(namestrip(name))
if entry and entry.help():
return 1
# This catches names that are in a helpfile but not known to CML2.
if not xrefs.has_key(name):
return 0
for file in xrefs[name]:
if suffix(file, ".help"):
return 1
# False negative if there is ever a choice name that CML2
# doesn't know about.
return 0
def in_cml2_help(name):
"Does a name occur in some help file (CML2 rules)?"
entry = rulebase.dictionary.get(namestrip(name))
if entry and entry.helptext:
return 1
# This catches names that are in a helpfile but not known to CML2.
if not xrefs.has_key(name):
return 0
for file in xrefs[name]:
if suffix(file, ".help"):
return 1
# False negative if there is ever a choice name that CML2
# doesn't know about.
return 0
def in_makefile(name):
"Does a name occur in a makefile?"
if not xrefs.has_key(name):
return 0
for file in xrefs[name]:
if suffix(file, "akefile"):
return 1
return 0
def in_cml1(name):
"Does a name occur in a CML1 file?"
if not xrefs.has_key(name):
return 0
for file in xrefs[name]:
if suffix(file, "onfig.in"):
return 1
return 0
def cml1_declared(name):
"Is a name declared (assigned a type) in a CML1 file?"
return mycml1types.has_key(name)
def in_defconfig(name):
if not xrefs.has_key(name):
return 0
"Does a this symbol occur in a defconfig?"
for file in xrefs[name]:
if file.find("defconfig") > -1 or file.find("configs/") > -1:
return 1
return 0
def in_cml2(name):
"Is this a valid CML2 symbol?"
return rulebase.dictionary.has_key(namestrip(name))
def is_derived(name):
"Is this a CML2 derived name?"
entry = rulebase.dictionary.get(namestrip(name))
if entry and entry.is_derived():
return 1
else:
return 0
def dependent_of(ancestor, name):
"Is given symbol a dependent of given ancestor?"
ancestor = rulebase.dictionary.get(namestrip(ancestor))
entry = rulebase.dictionary.get(namestrip(name))
if entry and ancestor.ancestor_of(entry):
return 1
else:
return 0
def ancestor_of(dependent, name):
"Is given symbol a an ancestor of given dependent?"
dependent = rulebase.dictionary.get(namestrip(dependent))
entry = rulebase.dictionary.get(namestrip(name))
if entry and entry.ancestor_of(dependent):
return 1
else:
return 0
def type_of(typename, name):
"Is given symbol of given tyoe?"
entry = rulebase.dictionary.get(namestrip(name))
if entry and entry.type == typename:
return 1
else:
return 0
def has_property(property, name):
"Does given symbol have given property?"
entry = rulebase.dictionary.get(namestrip(name))
if entry and property in entry.properties:
return 1
else:
return 0
def is_probed(name):
"Does given symbol have a probe?"
entry = rulebase.dictionary.get(namestrip(name))
if not probe_table:
load_probe_table()
return entry and probe_table.has_key(entry.name)
def in_visibility(guard, name):
"Does the symbol GUARD occur in the visibility predicate of NAME?"
entry = rulebase.dictionary.get(namestrip(name))
if not entry:
return 0
guard = rulebase.dictionary.get(namestrip(guard))
return entry.visibility and guard in cml.flatten_expr(entry.visibility)
# Report generation
def setfilter(filterspec):
"Set the filter function."
if not filterspec:
function = "def myfilter(name): return 1"
else:
state = 0
expression = ""
for c in filterspec:
if state == 0:
if c == "(" or c == ")":
expression += c
elif c == " " or c == "\t":
pass
elif c == "a":
expression += " cml1_declared(name)"
elif c == "c":
expression += " in_code(name)"
elif c == "h":
expression += " in_help(name)"
elif c == "H":
expression += " in_cml2_help(name)"
elif c == 'm':
expression += " in_makefile(name)"
elif c == "o":
expression += " in_cml1(name)"
elif c == "n":
expression += " in_cml2(name)"
elif c == "d":
expression += " in_defconfig(name)"
elif c == "x":
expression += " is_derived(name)"
elif c == "~":
expression += " not"
elif c == "&":
expression += " and"
elif c == "|":
expression += " or"
elif c == "p":
expression += " is_probed(name)"
elif c == "D":
expression += " dependent_of"
state = 1
elif c == "A":
expression += " ancestor_of"
state = 1
elif c == "T":
expression += " type_of"
state = 1
elif c == "P":
expression += " has_property"
state = 1
elif c == "V":
expression += " in_visibility"
state = 1
elif state == 1:
if c == ')':
expression += '", name)'
state = 0
elif c == '(':
expression += '("'
else:
expression += c
function = "def myfilter(name): return " + expression
#sys.stderr.write("Filter function: " + function + "\n")
exec function in globals()
def report(keys, norefs=0):
"Generate a filtered report on the cross-references."
for symbol in keys:
refs = filter(lambda x: not (suppress and suppress.search(x)), xrefs[symbol])
if refs:
if norefs:
print symbol
else:
sys.stdout.write(symbol + ":")
for file in refs:
sys.stdout.write(" " + file)
sys.stdout.write("\n")
def generate_patch(file, symbols):
"Generate a patch deleting the given symbols from the given file."
pfp = open(file, "rb")
contents = pfp.read()
pfp.close()
for symbol in symbols:
contents = re.compile("^.*" + symbol + "[^A-Z0-9].*\n", re.M).sub("", contents)
pfp = open(file + ".tweaked", "wb")
pfp.write(contents)
pfp.close()
os.system("diff -u %s %s.tweaked; rm %s.tweaked" % (file, file, file))
# Inclusion checking. This lives here because we use the CML2 rulebase to
# check which CONFIG_ symbols are defined (just checking for a CONFIG_ stem
# isn't reliable as CML2 doesn't completely own that namespace).
includere = re.compile(r'^\s*#\s*include\s*[<"](\S*)[>"]', re.M)
def includecheck(sourcetree):
"Check the inclusion structure of a source tree."
def includevisit(dummy, dir, files):
"Visit a directory on behalf of the inclusion checker."
def filevisitor(dummy, file):
"Visit a file on behalf of the inclusion checker."
fp = open(file)
contents = fp.read()
fp.close()
# First get the list of included files
inclusions = includere.findall(contents)
# This strips slashes, so it has to be done after
contents = c_comment_strip(contents)
# Check to see if we have defined CONFIG_ symbols in the file
matched = []
for match in configpref.findall(contents):
if suffix(match, "_MODULE"):
match = match[:-7]
match = namestrip(match) # Strip prefix
if rulebase.dictionary.has_key(match) and match not in matched:
matched.append(match)
# Check for duplicates
dups = {}
for header in inclusions:
dups[header] = 0
for header in inclusions:
dups[header] += 1
for header in inclusions:
if dups[header] > 1:
print "%s: %s is included %d times" % (file, header, dups[header])
# OK, check to see if we have autoconf inclusion.
have_autoconf = 0
for header in inclusions:
if header == "autoconf.h" or header == "linux/config.h":
have_autoconf = 1
break
if not matched and have_autoconf:
print "%s: has unnecessary configure file inclusion" % file
elif matched and not have_autoconf:
print "%s: needs configure file inclusion for %s" % (file, matched)
for file in files:
if suffix(file, ".c", ".h", ".S"):
node = os.path.join(dir, file)[2:]
if os.path.isfile(node) and not ignore(node):
filevisitor(None, node)
here = os.getcwd()
os.chdir(sourcetree)
os.path.walk(".", includevisit, None)
os.chdir(here)
# The main program
def load_context(tree):
"Load context, including CML2 rulebase and cross-reference database."
global rulebase, xrefs, mycml1types
# Get a CML2 rulebase.
if not os.path.exists(os.path.join(tree, "rules.out")):
print "This program requires a CML2 rulebase in the source tree."
raise SystemExit, 1
else:
rulebase = cmlsystem.CMLSystem(os.path.join(tree, "rules.out"))
# Try to find a saved cross-reference database. If no such database
# exists, generate one and cache it.
xref_file = os.path.join(tree, "xref.out")
if os.path.exists(xref_file):
sys.stderr.write("Reading cross-reference database...")
ifp = open(xref_file, "rb")
(xrefs, mycml1types) = cPickle.load(ifp)
ifp.close()
sys.stderr.write("done.\n")
else:
sys.stderr.write("Regenerating cross-reference database...")
(xrefs, mycml1types) = makexref(tree)
ofp = open(xref_file, "w")
cPickle.dump((xrefs, mycml1types), ofp, 1)
ofp.close()
sys.stderr.write("done.\n")
if __name__ == "__main__":
setfilter(None)
examine = ""
norefs = 0
typecheck = 0
suppress = None
rulesfile = None
invert = genpatch = checkincludes = 0
(options, arguments) = getopt.getopt(sys.argv[1:], "ef:ghik:ln:r:tx:")
for (switch, val) in options:
if switch == '-f':
setfilter(val)
elif switch == '-i':
invert = 1
elif switch == '-g':
invert = genpatch = 1
elif switch == '-h':
checkincludes = 1
elif switch == '-k':
fp = open(val, "r")
while 1:
line = fp.readline()
if not line:
break
kill_list[line.strip()] = 1
elif switch == '-l':
norefs = 1
elif switch == '-n':
suppress = re.compile(val)
elif switch == '-r':
rulesfile = val
elif switch == '-t':
typecheck = 1
elif switch == '-x':
examine = val
if len(arguments) < 1:
sourcetree = "."
else:
sourcetree = arguments[0]
# Load or regenerate the cross-reference database
load_context(sourcetree)
if not checkincludes:
# OK, now filter the database
keys = filter(myfilter, xrefs.keys())
keys.sort()
# If invert was specified, invert the database so it's keyed by file
if invert:
inverted = {}
for key in keys:
for file in xrefs[key]:
if not inverted.has_key(file):
inverted[file] = []
if key not in inverted[file]:
inverted[file].append(key)
xrefs = inverted
keys = inverted.keys()
keys.sort()
if genpatch:
for file in keys:
generate_patch(file, xrefs[file])
elif checkincludes:
includecheck(sourcetree)
elif examine:
shortname = namestrip(examine)
if not rulebase.dictionary.has_key(shortname) and not mycml1types.has_key(examine):
print "%s: no such symbol" % examine
else:
print "%s: a=%d c=%d h=%d o=%d n=%d m=%d d=%d x=%s f=%d" % (examine, cml1_declared(examine), in_code(examine), in_help(examine), in_cml1(examine), in_cml2(examine), in_makefile(examine), in_defconfig(examine), is_derived(examine), myfilter(examine))
elif typecheck:
print "CML1 type consistency report:"
hits = []
ok = 0
for (key, item) in mycml1types.items():
if len(item) == 1:
ok += 1
else:
hits.append(key)
print "%d symbols have consistent type declarations." % ok
if hits:
print "Non-declared or multiply-declared symbols:"
for symbol in hits:
print "%s:" % symbol
for (type, locs) in mycml1types[symbol]:
print " %-8s: %s" % (type, " ".join(locs))
print "CML2 type cross-check:"
typematch = 0
missing = 0
matching = 0
typemap = {"bool":"bool", "trit":"tristate", "string":"string", "decimal":"int", "hexadecimal":"hex"}
for (key, item) in mycml1types.items():
if not rulebase.dictionary.has_key(namestrip(key)):
missing += 1
continue
elif len(item) != 1:
continue
cml2symbol = rulebase.dictionary[namestrip(key)]
cml1type = item[0][0]
if typemap[cml2symbol.type] == cml1type:
matching += 1
elif cml2symbol.menu and cml2symbol.menu.type=="choices" and cml1type=="choice":
matching += 1
else:
if cml2symbol.is_derived():
derived = "(derived)"
else:
derived = ""
print '"%s", line %d: %s, %s -> %s %s' % (cml2symbol.file, cml2symbol.lineno, key, item[0][0], cml2symbol.type, derived)
print "%d CML1 symbols missing, %d type matches" % (missing, matching)
else:
# OK, list the filtered symbols
try:
report(keys, norefs)
except (KeyboardInterrupt, IOError):
pass # In case we break a pipe by interrupting
# That's all, folks!

479
tools/cml2-tools/tree.py Normal file
View File

@@ -0,0 +1,479 @@
# tree.py -- highly optimized tkinter tree control
# by Charles E. "Gene" Cash (gcash@magicnet.net)
#
# 98/12/02 CEC started
# 99/??/?? CEC release to comp.lang.python.announce
# Trimmed for CML2 by ESR, December 2001 (cut-paste support removed).
import os, string
from Tkinter import *
# this is initialized later, after Tkinter is started
open_icon=None
# tree node helper class
class Node:
# initialization creates node, draws it, and binds mouseclicks
def __init__(self, parent, name, id, myclosed_icon, myopen_icon, x, y,
parentwidget):
self.parent=parent # immediate parent node
self.name=name # name displayed on the label
self.id=id # internal id used to manipulate things
self.open_icon=myopen_icon # bitmaps to be displayed
self.closed_icon=myclosed_icon
self.widget=parentwidget # tree widget we belong to
self.subnodes=[] # our list of child nodes
self.spinlock=0 # cheap mutex spinlock
self.open_flag=0 # closed to start with
# draw horizontal connecting lines
if self.widget.lineflag:
self.line=self.widget.create_line(x-self.widget.distx, y, x, y)
# draw approprate image
if self.open_flag:
self.symbol=self.widget.create_image(x, y, image=self.open_icon)
else:
self.symbol=self.widget.create_image(x, y, image=self.closed_icon)
# add label
self.label=self.widget.create_text(x+self.widget.textoff, y,
text=self.name, justify='left',
anchor='w' )
# single-click to expand/collapse
self.widget.tag_bind(self.symbol, '<1>', self.click)
self.widget.tag_bind(self.label, '<1>', self.click) # njr
# call customization hook
if self.widget.init_hook:
self.widget.init_hook(self)
# def __repr__(self):
# return 'Node: %s Parent: %s (%d children)' % \
# (self.name, self.parent.name, len(self.subnodes))
# recursively delete subtree & clean up cyclic references
def _delete(self):
for i in self.subnodes:
if i.open_flag and i.subnodes:
# delete vertical connecting line
if self.widget.lineflag:
self.widget.delete(i.tree)
# delete node's subtree, if any
i._delete()
# the following unbinding hassle is because tkinter
# keeps a callback reference for each binding
# so if we want things GC'd...
for j in (i.symbol, i.label):
for k in self.widget.tag_bind(j):
self.widget.tag_unbind(j, k)
try:
for k in self.widget._tagcommands.get(j, []):
self.widget.deletecommand(k)
self.widget._tagcommands[j].remove(k)
except: # XXX not needed in >= 1.6?
pass
# delete widgets from canvas
self.widget.delete(i.symbol, i.label)
if self.widget.lineflag:
self.widget.delete(i.line)
# break cyclic reference
i.parent=None
# move cursor if it's in deleted subtree
if self.widget.pos in self.subnodes:
self.widget.move_cursor(self)
# now subnodes will be properly garbage collected
self.subnodes=[]
# move everything below current icon, to make room for subtree
# using the magic of item tags
def _tagmove(self, dist):
# mark everything below current node as movable
bbox1=self.widget.bbox(self.widget.root.symbol, self.label)
bbox2=self.widget.bbox('all')
self.widget.dtag('move')
self.widget.addtag('move', 'overlapping',
bbox2[0], bbox1[3], bbox2[2], bbox2[3])
# untag cursor & node so they don't get moved too
# this has to be done under Tk on X11
self.widget.dtag(self.widget.cursor_box, 'move')
self.widget.dtag(self.symbol, 'move')
self.widget.dtag(self.label, 'move')
# now do the move of all the tagged objects
self.widget.move('move', 0, dist)
# fix up connecting lines
if self.widget.lineflag:
n=self
while n:
if len(n.subnodes):
# position of current icon
x1, y1=self.widget.coords(n.symbol)
# position of last node in subtree
x2, y2=self.widget.coords(n.subnodes[-1:][0].symbol)
self.widget.coords(n.tree, x1, y1, x1, y2)
n=n.parent
# return list of subnodes that are expanded (not including self)
# only includes unique leaf nodes (e.g. /home and /home/root won't
# both be included) so expand() doesn't get called unnecessarily
# thank $DEITY for Dr. Dutton's Data Structures classes at UCF!
def expanded(self):
# push initial node into stack
stack=[(self, (self.id,))]
list=[]
while stack:
# pop from stack
p, i=stack[-1:][0]
del stack[-1:]
# flag to discard non-unique sub paths
flag=1
# check all children
for n in p.subnodes:
# if expanded, push onto stack
if n.open_flag:
flag=0
stack.append((n, i+(n.id,)))
# if we reached end of path, add to list
if flag:
list.append(i[1:])
return list
# get full name, including names of all parents
def full_id(self):
if self.parent:
return self.parent.full_id()+(self.id,)
else:
return (self.id,)
# expanding/collapsing folders
def toggle_state(self, state=None):
if self.widget.toggle_init_hook:
self.widget.toggle_init_hook(self)
if not self.open_icon:
return # not an expandable folder
if state == None:
state = not self.open_flag # toggle to other state
else:
# are we already in the state we want to be?
if (not state) == (not self.open_flag):
return
# not re-entrant
# acquire mutex
while self.spinlock:
pass
self.spinlock=1
# call customization hook
if self.widget.before_hook:
self.widget.before_hook(self)
# if we're closed, expand & draw our subtrees
if not self.open_flag:
self.open_flag=1
self.widget.itemconfig(self.symbol, image=self.open_icon)
# get contents of subdirectory or whatever
contents=self.widget.get_contents(self)
# move stuff to make room
self._tagmove(self.widget.disty*len(contents))
# now draw subtree
self.subnodes=[]
# get current position of icon
x, y=self.widget.coords(self.symbol)
yp=y
for i in contents:
# add new subnodes, they'll draw themselves
yp=yp+self.widget.disty
self.subnodes.append(Node(self, i[0], i[1], i[2], i[3],
x+self.widget.distx, yp,
self.widget))
# the vertical line spanning the subtree
if self.subnodes and self.widget.lineflag:
self.tree=self.widget.create_line(x, y,
x, y+self.widget.disty*len(self.subnodes))
self.widget.lower(self.tree, self.symbol)
# if we're open, collapse and delete subtrees
elif self.open_flag:
self.open_flag=0
self.widget.itemconfig(self.symbol, image=self.closed_icon)
# if we have any children
if self.subnodes:
# recursively delete subtree icons
self._delete()
# delete vertical line
if self.widget.lineflag:
self.widget.delete(self.tree)
# find next (vertically-speaking) node
n=self
while n.parent:
# position of next sibling in parent's list
i=n.parent.subnodes.index(n)+1
if i < len(n.parent.subnodes):
n=n.parent.subnodes[i]
break
n=n.parent
if n.parent:
# move everything up so that distance to next subnode is
# correct
x1, y1=self.widget.coords(self.symbol)
x2, y2=self.widget.coords(n.symbol)
dist=y2-y1-self.widget.disty
self._tagmove(-dist)
# update scroll region for new size
x1, y1, x2, y2=self.widget.bbox('all')
self.widget.configure(scrollregion=(x1, y1, x2+5, y2+5))
# call customization hook
if self.widget.after_hook:
print 'calling after_hook'
self.widget.after_hook(self)
# release mutex
self.spinlock=0
# expand this subnode
# doesn't have to exist, it expands what part of the path DOES exist
def expand(self, dirs):
# if collapsed, then expand
self.toggle_state(1)
# find next subnode
if dirs:
for n in self.subnodes:
if n.id == dirs[0]:
return n.expand(dirs[1:])
print "Can't find path %s in %s" % (dirs, self.id)
print "- Available subnodes: %s" % map(lambda n: n.id, self.subnodes)
return self
# handle mouse clicks by moving cursor and toggling folder state
def click(self, dummy):
self.widget.move_cursor(self)
self.toggle_state()
# return next lower visible node
def next(self):
n=self
if n.subnodes:
# if you can go right, do so
return n.subnodes[0]
while n.parent:
# move to next sibling
i=n.parent.subnodes.index(n)+1
if i < len(n.parent.subnodes):
return n.parent.subnodes[i]
# if no siblings, move to parent's sibling
n=n.parent
# we're at bottom
return self
# return next higher visible node
def prev(self):
n=self
if n.parent:
# move to previous sibling
i=n.parent.subnodes.index(n)-1
if i >= 0:
# move to last child
n=n.parent.subnodes[i]
while n.subnodes:
n=n.subnodes[-1]
else:
# punt if there's no previous sibling
if n.parent:
n=n.parent
return n
class Tree(Canvas):
def __init__(self, master, rootname, rootlabel=None, openicon=None,
shuticon=None, getcontents=None, init=None,
toggle_init=None,before=None, after=None, cut=None, paste=None,
distx=15, disty=15, textoff=10, lineflag=1, **kw_args):
global open_icon, shut_icon, file_icon,yes_icon,no_icon
# pass args to superclass
apply(Canvas.__init__, (self, master), kw_args)
# try creating an image, work around Tkinter bug
# ('global' should do it, but it doesn't)
if open_icon is not None:
try:
item = self.create_image(0,0,image=open_icon)
self.delete(item)
except:
print "recreating Tree PhotoImages"
open_icon = None # need to recreate PhotoImages
# default images (BASE64-encoded GIF files)
# we have to delay initialization until Tk starts up or PhotoImage()
# complains (otherwise I'd just put it up top)
if open_icon == None:
open_icon=PhotoImage(
data='R0lGODlhEAANAKIAAAAAAMDAwICAgP//////ADAwMAAAAAAA' \
'ACH5BAEAAAEALAAAAAAQAA0AAAM6GCrM+jCIQamIbw6ybXNSx3GVB' \
'YRiygnA534Eq5UlO8jUqLYsquuy0+SXap1CxBHr+HoBjoGndDpNAAA7')
shut_icon=PhotoImage(
data='R0lGODlhDwANAKIAAAAAAMDAwICAgP//////ADAwMAAAAAAA' \
'ACH5BAEAAAEALAAAAAAPAA0AAAMyGCHM+lAMMoeAT9Jtm5NDKI4Wo' \
'FXcJphhipanq7Kvu8b1dLc5tcuom2foAQQAyKRSmQAAOw==')
file_icon=PhotoImage(
data='R0lGODlhCwAOAJEAAAAAAICAgP///8DAwCH5BAEAAAMALAAA' \
'AAALAA4AAAIphA+jA+JuVgtUtMQePJlWCgSN9oSTV5lkKQpo2q5W+' \
'wbzuJrIHgw1WgAAOw==')
yes_icon=PhotoImage(
data='R0lGODlhDAAPAKEAAP////9FRAAAAP///yH5BAEKAAMALAAA' \
'AAAMAA8AAAIrhI8zyKAWUARCQGnqPVODuXlg0FkQ+WUmUzYpZYKv9'\
'5Eg7VZKxffC7usVAAA7')
no_icon=PhotoImage(
data='R0lGODlhDAAPAKEAAP///wAAAERe/////yH+FUNyZWF0ZWQgd' \
'2l0aCBUaGUgR0lNUAAh+QQBCgADACwAAAAADAAPAAACLISPM8i' \
'gjUIAolILpDB70zxxnieJBxl6n1FiGLiuW4tgJcSGuKRI/h/oAX8FADs=')
# function to return subnodes (not very much use w/o this)
if not getcontents:
raise ValueError, 'must have "get_contents" function'
self.get_contents=getcontents
# horizontal distance that subtrees are indented
self.distx=distx
# vertical distance between rows
self.disty=disty
# how far to offset text label
self.textoff=textoff
# called after new node initialization
self.init_hook=init
# called right after toggle state
self.toggle_init_hook=toggle_init
# called just before subtree expand/collapse
self.before_hook=before
# called just after subtree expand/collapse
self.after_hook=after
# flag to display lines
self.lineflag=lineflag
# create root node to get the ball rolling
if openicon:
oi = openicon
else:
oi = open_icon
if shuticon:
si = shuticon
else:
si = shut_icon
if rootlabel:
self.root=Node(None, rootlabel, rootname, si, oi, 11, 11, self)
else:
self.root=Node(None, rootname, rootname, si, oi, 11, 11, self)
# configure for scrollbar(s)
x1, y1, x2, y2=self.bbox('all')
self.configure(scrollregion=(x1, y1, x2+5, y2+5))
# add a cursor
self.cursor_box=self.create_rectangle(0, 0, 0, 0)
self.move_cursor(self.root)
# make it easy to point to control
self.bind('<Enter>', self.mousefocus)
# bindings similar to those used by Microsoft tree control
# page-up/page-down
self.bind('<Next>', self.pagedown)
self.bind('<Prior>', self.pageup)
# arrow-up/arrow-down
self.bind('<Down>', self.next)
self.bind('<Up>', self.prev)
# arrow-left/arrow-right
self.bind('<Left>', self.ascend)
# (hold this down and you expand the entire tree)
self.bind('<Right>', self.descend)
# home/end
self.bind('<Home>', self.first)
self.bind('<End>', self.last)
# space bar
self.bind('<Key-space>', self.toggle)
# scroll (in a series of nudges) so items are visible
def see(self, *items):
x1, y1, x2, y2=apply(self.bbox, items)
while x2 > self.canvasx(0)+self.winfo_width():
old=self.canvasx(0)
self.xview('scroll', 1, 'units')
# avoid endless loop if we can't scroll
if old == self.canvasx(0):
break
while y2 > self.canvasy(0)+self.winfo_height():
old=self.canvasy(0)
self.yview('scroll', 1, 'units')
if old == self.canvasy(0):
break
# done in this order to ensure upper-left of object is visible
while x1 < self.canvasx(0):
old=self.canvasx(0)
self.xview('scroll', -1, 'units')
if old == self.canvasx(0):
break
while y1 < self.canvasy(0):
old=self.canvasy(0)
self.yview('scroll', -1, 'units')
if old == self.canvasy(0):
break
# move cursor to node
def move_cursor(self, node):
self.pos=node
x1, y1, x2, y2=self.bbox(node.symbol, node.label)
self.coords(self.cursor_box, x1-1, y1-1, x2+1, y2+1)
self.see(node.symbol, node.label)
# expand given path
# note that the convention used in this program to identify a
# particular node is to give a tuple listing it's id and parent ids
# so you probably want to use os.path.split() a lot
def expand(self, path):
return self.root.expand(path[1:])
# soak up event argument when moused-over
# could've used lambda but didn't...
def mousefocus(self, event):
self.focus_set()
# open/close subtree
def toggle(self, event=None):
self.pos.toggle_state()
# move to next lower visible node
def next(self, event=None):
self.move_cursor(self.pos.next())
# move to next higher visible node
def prev(self, event=None):
self.move_cursor(self.pos.prev())
# move to immediate parent
def ascend(self, event=None):
if self.pos.parent:
# move to parent
self.move_cursor(self.pos.parent)
# move right, expanding as we go
def descend(self, event=None):
self.pos.toggle_state(1)
if self.pos.subnodes:
# move to first subnode
self.move_cursor(self.pos.subnodes[0])
else:
# if no subnodes, move to next sibling
self.next()
# go to root
def first(self, event=None):
# move to root node
self.move_cursor(self.root)
# go to last visible node
def last(self, event=None):
# move to bottom-most node
n=self.root
while n.subnodes:
n=n.subnodes[-1]
self.move_cursor(n)
# previous page
def pageup(self, event=None):
n=self.pos
j=self.winfo_height()/self.disty
for i in range(j-3):
n=n.prev()
self.yview('scroll', -1, 'pages')
self.move_cursor(n)
# next page
def pagedown(self, event=None):
n=self.pos
j=self.winfo_height()/self.disty
for i in range(j-3):
n=n.next()
self.yview('scroll', 1, 'pages')
self.move_cursor(n)
# End

144
tools/cml2header.py Executable file
View File

@@ -0,0 +1,144 @@
#!/usr/bin/python
import os
import sys
import re
import StringIO
import getopt
class cml2header_translator:
'''
Translates a cml2 configuration file to a C header file
that can be included in source code.
'''
def __init__(self):
self.isnotset = re.compile("^# (.*) is not set")
def linetrans(self, instream, outstream, trailer=None):
'''
Translates a stream line-by-line
'''
if not hasattr(instream, "readline"):
instream = open(instream, "r")
if not hasattr(outstream, "readline"):
outstream = open(outstream, "w")
while 1:
line = instream.readline()
if not line:
break
new = self.write_include(line)
if new:
outstream.write(new)
instream.close()
if trailer:
outstream.write(trailer)
outstream.close()
def write_include(self, line):
'''
Translate a line of CML2 config file statement into
C preprocessor #define format.
'''
if line.find("PRIVATE") > -1 or line[:2] == "$$":
return ""
match = self.isnotset.match(line)
if match:
return "#undef %s\n" % match.group(1)
if line == "#\n":
return None
elif line[0] == "#":
return "/* " + line[1:].strip() + " */\n"
eq = line.find("=")
if eq == -1:
return line
else:
line = line.split('#')[0]
symbol = line[:eq]
value = line[eq+1 :].strip()
if value == 'y':
return "#define %s 1\n" % symbol
elif value == 'm':
return "#undef %s\n#define %s_MODULE 1\n" % (symbol, symbol)
elif value == 'n':
return "#undef %s\n" % symbol
else:
return "#define %s %s\n" % (symbol, value)
def cml_configfile_exists(self, path):
if not os.path.exists(path):
print "CML2 configuration file not found."
print "Given path:", path, "does not exist."
return 0
else:
return 1
def translate(self, configfile_path = None, headerfile_path = None):
if configfile_path == None:
configfile_path = os.getcwd() + '/' + "config.out"
if headerfile_path == None:
headerfile_path = os.getcwd() + '/' + "config.h"
'''
Takes a configuration file generated by the cml2 configurator,
and converts it to a C header file. This header file is then
included by the kernel sources and the preprocessor definitions
in it are used during the compilation of the kernel.
'''
if not self.cml_configfile_exists(configfile_path):
print "Failed to translate cml configuration file", configfile_path, 'to', headerfile_path
return -1
self.linetrans(configfile_path, headerfile_path)
return 0
def usage(self):
helpstr = \
'''\
Description:
cml2header.py takes a cml2 configuration file as input and generates
a valid C header file to be included in C source code.
Usage:
cml2header.py -i inputfile -o outputfile [-h]
Options:
-i The CML2 configuration file (config.out by default)
-o The name of the header file (config.h by default)
-h This help message
'''
print helpstr
def main():
translator = cml2header_translator()
try:
opts, args = getopt.getopt(sys.argv[1:], "i:o:h:")
except getopt.GetoptError:
# print help information and exit:
translator.usage()
sys.exit(2)
ofile = None
ifile = None
# Print help message if requested and quit
if '-h' in opts:
translator.usage()
sys.exit()
# Get the input and output filenames.
for switch, val in opts:
if switch == '-i':
ifile = val
if switch == '-o':
ofile = val
# Translate
if translator.translate(ifile, ofile) < 0:
print "Translation of", ifile, 'to', ofile, 'failed.'
# Run the main routine only if this file is explicitly executed.
# (i.e. not referred from another module)
if __name__ == "__main__":
main()

BIN
tools/cml2header.pyc Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
for filename in `find ./ -name '*.[ch]'`
do
sed -i -e "s/ORIGINAL/REPLACEMENT/g" $filename
done

63
tools/ksym_to_lds.py Executable file
View File

@@ -0,0 +1,63 @@
#!/usr/bin/python
import os
import sys
from string import atoi
from os import popen2
from os.path import join
symbols = ['bkpt_phys_to_virt']
builddir = "build"
loaderdir = "loader"
image = "start.axf"
imgpath = join(builddir, image)
asmfile = join(loaderdir, image) + ".S"
symfile = "ksyms"
asmheader = \
'''
/*
* %s autogenerated from %s
*
* This file is included by the loader sources so that any
* kernel symbol address can be known in advance and stopped
* at by debuggers before virtual memory is enabled.
*/
'''
asmcontent = \
'''
.section .text
.align 4
.global %s;
.type %s, function;
.equ %s, %s
'''
def virt_to_phys(addr):
return hex(int(addr, 16) - 0xF0000000)[:-1]
def ksym_to_lds():
asm = open(asmfile, "w+")
asm.write(asmheader % (asmfile, imgpath))
cmd = "arm-none-eabi-objdump -d " + imgpath + " | grep " + "\\<" + symbols[0] + "\\>" + " > " + symfile
os.system(cmd)
kf = open(symfile, "r")
#child_out, child_in = popen2(cmd)
while True:
line = kf.readline()
if len(line) is 0:
break
addr, sym = line.split()
sym = sym[1:-2]
addr = "0x" + addr
addr = virt_to_phys(addr)
if sym in symbols:
print "Adding " + sym + " from " + imgpath + " to " + asmfile + " in physical"
asm.write(asmcontent % (sym, sym, sym, addr))
asm.close()
kf.close()
cmd = "rm -rf " + symfile
os.system(cmd)
if __name__ == "__main__":
ksym_to_lds()

14
tools/l4-qemu Executable file
View File

@@ -0,0 +1,14 @@
cd build
#arm-none-eabi-insight &
qemu-system-arm -M versatilepb -kernel final.axf -nographic -s &
sleep 0.5
arm-none-eabi-insight ; pkill qemu-system-arm
#arm-none-eabi-gdb ; pkill qemu-system-arm
cd ..
# TODO:
# insight works ok if gdbinit script is run from the insight
# command window. Then one needs to break at bkpt_phys_to_virt and do:
# sym start.axf
# Then continue execution to see all symbols. This must be done automatic.

0
tools/pyelf/__init__.py Normal file
View File

327
tools/pyelf/aistruct.py Normal file
View File

@@ -0,0 +1,327 @@
import mmap
import struct
import os
class GFile(object):
def __init__(self, filename, size):
handle = open(filename, 'rb+')
self.mapping = mmap.mmap(handle.fileno(), size)
def set_byte_ordering(self, ordering):
self.byte_ordering = ordering
def get_byte_ordering(self):
return self.byte_ordering
def create_new(filename, size):
assert size < 10240 # This is only for testing, really
handle = open(filename, 'wb')
handle.write('\0' * size)
handle.close()
return GFile(filename, size)
create_new = staticmethod(create_new)
def existing(filename):
assert os.path.exists(filename)
size = os.path.getsize(filename)
return GFile(filename, size)
existing = staticmethod(existing)
class BitPoker(object):
""" """
SIZE_MAP = {1: 'B',
2: 'H',
4: 'I',
8: 'Q'}
def set_mmapfile(self, mmapfile, offset_bytes = 0):
self.mmapfile = mmapfile
self.master_offset_bytes = offset_bytes
def set_byte_ordering(self, byte_ordering):
self.byte_ordering = byte_ordering
self.struct_byte_ordering = {'lsb': '<', 'msb': '>'}[byte_ordering]
def get_byte_ordering(self):
return self.byte_ordering
def read_value(self, numbytes, offset_bytes):
# Seek to the right spot using absolute (whence=0) positioning
self.mmapfile.seek(offset_bytes + self.master_offset_bytes, 0)
data = self.mmapfile.read(numbytes)
return struct.unpack('%s%s' % (self.struct_byte_ordering,
self.SIZE_MAP[numbytes]), data)
def write_value_sized(self, value, numbytes, offset_bytes):
data = struct.pack('%s%s' % (self.struct_byte_ordering,
self.SIZE_MAP[numbytes]), value)
self.mmapfile.seek(offset_bytes + self.master_offset_bytes, 0)
self.mmapfile.write(data)
def read_value_sized(self, numbytes, offset_bytes):
self.mmapfile.seek(offset_bytes + self.master_offset_bytes, 0)
raw_data = self.mmapfile.read(numbytes)
data = struct.unpack('%s%s' % (self.struct_byte_ordering,
self.SIZE_MAP[numbytes]), raw_data)
return data[0]
def read_c_string(self, offset_bytes):
self.mmapfile.seek(offset_bytes + self.master_offset_bytes.get(), 0)
result = ''
c = self.mmapfile.read_byte()
while c != '\0':
result += c
c = self.mmapfile.read_byte()
return result
def new_with_gfile(gfile, offset):
poker = BitPoker()
poker.set_mmapfile(gfile.mapping, offset)
poker.set_byte_ordering(gfile.get_byte_ordering())
return poker
new_with_gfile = staticmethod(new_with_gfile)
def new_with_poker(origpoker, offset):
poker = BitPoker()
poker.set_mmapfile(origpoker.mmapfile, origpoker.master_offset_bytes + offset)
poker.set_byte_ordering(origpoker.get_byte_ordering())
return poker
new_with_poker = staticmethod(new_with_poker)
class AIStruct(object):
SIZE32 = 32
SIZE64 = 64
class AIElement(object):
_natural_size = None
def __init__(self, word_size_in_bits, offset, names, format):
self.offset = offset #offset into memory-mapped file.
self.set_target_word_size(word_size_in_bits)
self.value = 0
self.names = names
self.format = format
def set_target_word_size(self, target_word_size):
self.target_word_size = target_word_size
def get_size_bits(self):
return self._natural_size
def set_args(self):
pass
def set(self, value):
if type(value) is str and len(value) == 1:
value = ord(value)
self.value = value
def get(self):
return self.value
def write(self, bitpoker):
bitpoker.write_value_sized(self.value, self.get_size_bits() / 8,
self.offset)
def read(self, bitpoker):
self.value = bitpoker.read_value_sized(self.get_size_bits() / 8, self.offset)
def __cmp__(self, value):
return cmp(self.value, value)
def __add__(self, other):
if isinstance(other, AIStruct.AIElement):
return self.value + other.value
else:
return self.value + other
def __mul__(self, other):
if isinstance(other, AIStruct.AIElement):
return self.value * other.value
else:
return self.value * other
def __str__(self):
if self.format:
if type(self.format) == type(""):
return self.format % self.value
else:
return self.format(self.value)
if self.names:
return self.names.get(self.value, str(self.value))
else:
return str(self.value)
class WORD(AIElement):
def get_size_bits(self):
return self.target_word_size
class INT8(AIElement):
_natural_size = 8
UINT8 = INT8
class INT16(AIElement):
_natural_size = 16
UINT16 = INT16
class INT32(AIElement):
_natural_size = 32
UINT32 = INT32
class INT64(AIElement):
_natural_size = 64
UINT64 = INT64
class BITFIELD(AIElement):
class AttributeBasedProperty(object):
def __init__(self, bitfield_inst):
self.bitfield_inst = bitfield_inst
def get_length_and_offset_for_key(self, key):
offset = 0
length = 0
for name, sizes_dict in self.bitfield_inst.components:
if name == key:
length = sizes_dict[self.bitfield_inst.target_word_size]
break
offset += sizes_dict[self.bitfield_inst.target_word_size]
if length == 0:
raise AttributeError(key)
return length, offset
def __getitem__(self, key):
length, offset = self.get_length_and_offset_for_key(key)
# We have the position of the desired key in value.
# Retrieve it by right-shifting by "offset" and
# then masking away anything > length.
result = self.bitfield_inst.value >> offset
result &= ( (1<<length) - 1)
if self.bitfield_inst.post_get is not None:
return self.bitfield_inst.post_get(key, result)
else:
return result
def __setitem__(self, key, new_value):
if self.bitfield_inst.pre_set is not None:
new_value = self.bitfield_inst.pre_set(key, new_value)
length, offset = self.get_length_and_offset_for_key(key)
assert new_value < (1 << length)
# Generate the result in three stages
# ... insert the new value:
result = new_value << offset
# ... | the stuff above the value:
result |= ( self.bitfield_inst.value >> (offset + length) << (offset + length) )
# ... | the stuff below the value.
result |= ( self.bitfield_inst.value & ( (1 << offset) - 1 ) )
self.bitfield_inst.value = result
def __init__(self, *args, **kwargs):
super(AIStruct.BITFIELD, self).__init__(*args, **kwargs)
self.components = []
self.attribute_based_property = AIStruct.BITFIELD.AttributeBasedProperty(self)
def set_args(self, components=None, post_get=None, pre_set=None):
if components is not None:
self.components = components
self.post_get = post_get
self.pre_set = pre_set
def get_size_bits(self):
size_bits = 0
for comp_name, comp_sizes in self.components:
size_bits += comp_sizes[self.target_word_size]
return size_bits
def get(self):
return self.attribute_based_property
def set(self, value):
raise AttributeError("set() shouldn't be called here!")
def __init__(self, word_size_in_bits):
self.word_size_in_bits = word_size_in_bits
self.thestruct = []
def _setup_attributes(self, allprops):
# So Python sucks and you can only set properties on class objects,
# not class instance objects. Hence this crud...
class AI(object):
pass
for key in allprops:
setattr(AI, key, allprops[key])
self.ai = AI()
def _setup_one(self, etypename, ename, args, offset, names, format):
elementclass = getattr(self, etypename)
elementinst = elementclass(self.word_size_in_bits, offset, names, format)
elementinst.set_args(**args)
self.thestruct.append(elementinst)
def get_item(obj):
return elementinst
def set_item(obj, value):
return elementinst.set(value)
newprop = {'%s' % (ename): property(get_item, set_item)}
return (elementinst.get_size_bits() / 8, newprop)
def _setup_multiprop(self, ename, times):
def mp_get(obj):
return [getattr(self.ai, '%s_%s' % (ename, counter)) for counter in range(1, times+1)]
def mp_set(obj, value):
for num, item in enumerate(value):
setattr(self.ai, '%s_%s' % (ename, num + 1), item)
return {'%s' % (ename): property(mp_get, mp_set)}
def setup(self, *elements):
offset = 0
allprops = {}
for element in elements:
etypename, ename = element[:2]
args = {}
if len(element) == 3:
args = element[2]
times = args.get('times', None)
names = args.get('names', None)
format = args.get('format', None)
if names is not None:
del args['names']
if format is not None:
del args['format']
if times is not None:
del args['times']
for time in range(times):
size, propdict = self._setup_one(etypename, '%s_%s' % (ename, time + 1), args, offset, names, format)
offset += size
allprops.update(propdict)
allprops.update(self._setup_multiprop(ename, times))
else:
size, propdict = self._setup_one(etypename, ename, args, offset, names, format)
offset += size
allprops.update(propdict)
self._setup_attributes(allprops)
def struct_size(self):
size = 0
for element in self.thestruct:
size += element.get_size_bits()
return size / 8
def set_poker(self, poker):
self.poker = poker
def write(self):
for element in self.thestruct:
element.write(self.poker)
def read_from_poker(self, poker):
self.set_poker(poker)
for element in self.thestruct:
element.read(self.poker)
def write_new(self, filename):
"""convenience function to create a new file and store the KCP in it. """
newfile = GFile.create_new(filename, self.struct_size())
poker = BitPoker('lsb') #FIXME
poker.set_mmapfile(newfile.mapping, offset_bytes = 0)
self.set_poker(poker)
self.write()

BIN
tools/pyelf/aistruct.pyc Normal file

Binary file not shown.

84
tools/pyelf/burn.py Normal file
View File

@@ -0,0 +1,84 @@
from aistruct import AIStruct
import elf, sys
from optparse import OptionParser
class AfterBurner(AIStruct):
def __init__(self, *args, **kwargs):
AIStruct.__init__(self, AIStruct.SIZE32)
self.setup(
('UINT32', 'addr')
)
def __str__(self):
return "0x%x" % self.ai.addr.get()
def arch_perms(rwx):
# ia32 doesn't support read-noexec
if rwx & (1 << 2):
rwx |= 1
return rwx
def align_up(value, align):
mod = value % align
if mod != 0:
value += (align - mod)
return value
def gen_pheaders(elf):
old_rwx = 0
old_offset = 0
old_addr = 0
old_bits = 0
old_size = 0
new_addr = 0
new_offset = 0
new_size = 0
for section in [section for section in elf.sheaders if section.allocable()]:
# Test - can we add this section to the current program header?
new = 0
rwx = arch_perms(section.get_perms())
addr = section.ai.sh_addr.get()
offset = section.ai.sh_offset.get()
al = section.ai.sh_addralign.get()
size = section.ai.sh_size.get()
if old_rwx != rwx:
new = 1
if addr != align_up(old_size + old_addr, al):
new = 2
if offset != align_up(old_size + old_offset, al):
new = 3
if new != 0:
#print hex(new_offset), hex(new_addr), hex(new_size)
new_size = size
new_addr = addr
new_offset = offset
else:
new_size = (addr + size) - new_addr
old_rwx = rwx
old_size = size
old_bits = 0
old_offset = offset
old_addr = addr
#print section.ai.sh_name, section.ai.sh_addr, section.ai.sh_offset, section.ai.sh_size, section.ai.sh_flags, rwx
print hex(new_offset), hex(new_addr), hex(new_size)
def main():
wedge = elf.ElfFile.from_file(sys.argv[1])
guest = elf.ElfFile.from_file(sys.argv[2])
print wedge.pheaders
for section in wedge.sheaders:
print section.name
section.name += ".linux"
print section.name
#del wedge.pheaders[:]
#print wedge.pheaders
wedge.write_file("foobar")
gen_pheaders(wedge)
if __name__ == "__main__":
main()

500
tools/pyelf/elf.py Normal file
View File

@@ -0,0 +1,500 @@
from aistruct import GFile, BitPoker, AIStruct
import StringIO
import sys
class Elf32Header(AIStruct):
EI_MAGIC = [0x7f, ord('E'), ord('L'), ord('F')]
EI_CLASS_32 = 1
EI_CLASS_64 = 2
EI_DATA_LSB = 1
EI_DATA_MSB = 2
EI_TYPE_NONE = 0
EI_TYPE_REL = 1
EI_TYPE_EXEC = 2
EI_TYPE_DYN = 3
EI_TYPE_CORE = 4
EI_TYPE_NUM = 5
EI_TYPE_LOPROC = 0xff00
EI_TYPE_HIPROC = 0xffff
MACHINE_NONE = 0
MACHINE_SPARC = 2
MACHINE_386 = 3
MACHINE_MIPS = 8
MACHINE_MIPS_RS4_BE = 10
MACHINE_SPARC32PLUS = 18
MACHINE_ARM = 40
MACHINE_FAKE_ALPHA = 41
MACHINE_SPARCV9 = 43
MACHINE_IA_64 = 50
MACHINE_ALPHA = 0x9026
VERSION_NONE = 0
VERSION_CURRENT = 1
def __init__(self):
AIStruct.__init__(self, AIStruct.SIZE32)
self.setup(
('UINT8', 'ei_magic', {'times': 4}),
('UINT8', 'ei_class', {'names' : { 1: "ELF32", 2: "ELF64" }} ),
('UINT8', 'ei_data', {'names' : { 1 : "2's complement, little endian", 2: "2's complement, big endian" }}),
('UINT8', 'ei_version', {'names' : { 1 : "1 (current)" }}),
('UINT8', 'ei_osabi', { 'names' : { 0 : "UNIX - System V", 1 : "HP-UX Operating System", 255 : "Standalone application"}}),
('UINT8', 'ei_abiversion'),
('UINT8', 'ei_padding', {'times': 7}),
('UINT16', 'e_type', { 'names' : { 2 : "EXEC (Executable file)" }} ),
('UINT16', 'e_machine', { 'names' : { 3 : "Intel 80836" } }),
('UINT32', 'e_version', {'format': "0x%x" }),
('UINT32', 'e_entry', {'format': "0x%x" }),
('UINT32', 'e_phoff', { 'format' : "%d (bytes into file)" }),
('UINT32', 'e_shoff', { 'format' : "%d (bytes into file)" }),
('UINT32', 'e_flags', {'format': "0x%x" }),
('UINT16', 'e_ehsize', { 'format' : "%d (bytes)" } ),
('UINT16', 'e_phentsize', { 'format' : "%d (bytes)" } ),
('UINT16', 'e_phnum'),
('UINT16', 'e_shentsize', { 'format' : "%d (bytes)" } ),
('UINT16', 'e_shnum'),
('UINT16', 'e_shstrndx')
)
def __str__(self):
f = StringIO.StringIO()
f.write("ELF Header:\n")
for name, attr in [("Class", "ei_class"),
("Data", "ei_data"),
("Version", "ei_version"),
("OS/ABI", "ei_osabi"),
("ABI Version", "ei_abiversion"),
("Type", "e_type"),
("Machine", "e_machine"),
("Version", "e_version"),
("Entry point address", "e_entry"),
("Start of program headers", "e_phoff"),
("Start of section headers", "e_shoff"),
("Flags", "e_flags"),
("Size of this header", "e_ehsize"),
("Size of program headers", "e_phentsize"),
("Number of program headers", "e_phnum"),
("Size of section headers", "e_shentsize"),
("Number of section headers", "e_shnum"),
("Section header string table index", "e_shstrndx"),
]:
f.write(" %-35s%s\n" % ("%s:" % name, getattr(self.ai, attr)))
return f.getvalue()
class Elf64Header(Elf32Header):
# Inherit from Elf32Header to get the constants.
def __init__(self):
AIStruct.__init__(self, AIStruct.SIZE64)
self.setup(
('UINT8', 'ei_magic', {'times': 4}),
('UINT8', 'ei_class'),
('UINT8', 'ei_data'),
('UINT8', 'ei_version'),
('UINT8', 'ei_padding', {'times': 9}),
('UINT16', 'e_type'),
('UINT16', 'e_machine'),
('UINT32', 'e_version'),
('UINT64', 'e_entry'),
('UINT64', 'e_phoff'),
('UINT64', 'e_shoff'),
('UINT32', 'e_flags'),
('UINT16', 'e_ehsize'),
('UINT16', 'e_phentsize'),
('UINT16', 'e_phnum'),
('UINT16', 'e_shentsize'),
('UINT16', 'e_shnum'),
('UINT16', 'e_shstrndx')
)
class Elf32SectionHeader(AIStruct):
SHF_WRITE = 1 << 0
SHF_ALLOC = 1 << 1
SHF_EXECINSTR = 1 << 2
def __init__(self, *args, **kwargs):
AIStruct.__init__(self, AIStruct.SIZE32)
self.elffile = kwargs["elffile"]
self.index = kwargs["index"]
def format_flags(x):
if x == (self.SHF_WRITE | self.SHF_ALLOC):
return "WA"
if x == (self.SHF_EXECINSTR | self.SHF_ALLOC):
return "AX"
if x == self.SHF_WRITE:
return "W"
if x == self.SHF_ALLOC:
return "A"
if x == self.SHF_EXECINSTR:
return "X"
return "%x" % x
self.mutated = 0
self._name = None
self.setup(
('UINT32', 'sh_name', {"format" : self.elffile.get_name}),
('UINT32', 'sh_type', {"names" : {0:"NULL", 1:"PROGBITS", 2:"SYMTAB", 3:"STRTAB", 8:"NOBITS"}}),
('UINT32', 'sh_flags', {"format": format_flags}),
('UINT32', 'sh_addr', {"format" : "%08x"}),
('UINT32', 'sh_offset', {"format" : "%06x"}),
('UINT32', 'sh_size', {"format" : "%06x"}),
('UINT32', 'sh_link'),
('UINT32', 'sh_info', {"format" : "%3d"}),
('UINT32', 'sh_addralign', {"format" : "%2d"}),
('UINT32', 'sh_entsize', {"format" : "%02x"}),
)
def get_name(self):
if not self._name:
self._name = self.elffile.get_name(self.ai.sh_name)
return self._name
def set_name(self, value):
self._name = value
name = property(get_name, set_name)
def get_sym_name(self, value):
strtab = ElfFileStringTable \
(self.elffile.gfile, self.elffile.sheaders[self.ai.sh_link.get()])
return strtab.read(value)
def allocable(self):
return self.ai.sh_flags.get() & self.SHF_ALLOC
def writable(self):
return self.ai.sh_flags.get() & self.SHF_WRITE
def executable(self):
return self.ai.sh_flags.get() & self.SHF_EXECINSTR
def get_perms(self):
# Only call on allocatable
assert self.allocable()
rwx = (1 << 2);
if self.writable():
rwx |= (1 << 1)
if self.executable():
rwx |= 1
return rwx
def container(self, cls):
size = cls(section = self).struct_size()
return ElfFileContainer(self.elffile.gfile, AIStruct.SIZE32, self.ai.sh_offset.get(),
size, self.ai.sh_size.get() / size,
cls, section=self)
class Elf64SectionHeader(AIStruct):
def __init__(self, *args, **kwargs):
AIStruct.__init__(self, AIStruct.SIZE64)
self.setup(
('UINT32', 'sh_name'),
('UINT32', 'sh_type'),
('UINT64', 'sh_flags'),
('UINT64', 'sh_addr'),
('UINT64', 'sh_offset'),
('UINT64', 'sh_size'),
('UINT32', 'sh_link'),
('UINT32', 'sh_info'),
('UINT64', 'sh_addralign'),
('UINT64', 'sh_entsize'),
)
class Elf32ProgramHeader(AIStruct):
PT_NULL = 0
PT_NULL = 0
PT_LOAD = 1
PT_DYNAMIC = 2
PT_INTERP = 3
PT_NOTE = 4
PT_SHLIB = 5
PT_PHDR = 6
PT_NUM = 7
PT_LOOS = 0x60000000
PT_HIOS = 0x6fffffff
PT_LOPROC = 0x70000000
PT_HIPROC = 0x7fffffff
PF_X = 1 << 0
PF_W = 1 << 1
PF_R = 1 << 2
PF_MASKPROC = 0xf0000000L
def __init__(self, *args, **kwargs):
AIStruct.__init__(self, AIStruct.SIZE32)
self.elffile = kwargs["elffile"]
def format_flags(x):
the_str = [' ', ' ', ' ']
if (x & self.PF_X):
the_str[2] = 'E'
if (x & self.PF_W):
the_str[1] = 'W'
if (x & self.PF_R):
the_str[0] = 'R'
return "".join(the_str)
self.setup(
('UINT32', 'p_type', {"names" :
{0: "NULL",
1: "LOAD",
2 : "DYNAMIC",
3 : "INTERP",
4 : "NOTE",
1685382481 : "GNU_STACK",
1694766464 : "PAX_FLAGS",
}
} ),
('UINT32', 'p_offset', {"format": "0x%06x"}),
('UINT32', 'p_vaddr', {"format": "0x%08x"}),
('UINT32', 'p_paddr', {"format": "0x%08x"}),
('UINT32', 'p_filesz', {"format": "0x%05x"}),
('UINT32', 'p_memsz', {"format": "0x%05x"}),
('UINT32', 'p_flags', {"format": format_flags}),
('UINT32', 'p_align', {"format": "0x%x"}),
)
class Elf64ProgramHeader(Elf32ProgramHeader):
def __init__(self, *args, **kwargs):
AIStruct.__init__(self, AIStruct.SIZE64)
self.setup(
('UINT32', 'p_type', {"names" : {0: "NULL", 1: "LOAD", 2 : "DYNAMIC", 3 : "INTERP", 4 : "NOTE"}} ),
('UINT32', 'p_flags'),
('UINT64', 'p_offset'),
('UINT64', 'p_vaddr'),
('UINT64', 'p_paddr'),
('UINT64', 'p_filesz'),
('UINT64', 'p_memsz'),
('UINT64', 'p_align'),
)
class ElfFileException(Exception):
pass
class ElfFileNotElfException(ElfFileException):
pass
class ElfFileContainer(object):
def __init__(self, gfile, word_size, offset, entsize, number, cls, **kwargs):
self.gfile = gfile
self.word_size = word_size
self.offset = offset
self.entsize = entsize
self.number = number
self.cls = cls
self.mutated = 0
self.container = []
self.kwargs = kwargs
def mutate(self):
print "Making it mutable"
for each in self:
self.container.append(each)
self.mutated = 1
def __delitem__(self, idx):
if not self.mutated: self.mutate()
self.container.__delitem__(idx)
def __getitem__(self, idx):
if type(idx) == type(""):
# Act like a dictionary
for each in self:
if str(each.ai.sh_name) == idx:
return each
raise "badness"
else:
if self.mutated:
print "mutated", idx, self.container
return self.container[idx]
else:
num = idx
assert num >= 0
if num >= self.number:
raise StopIteration()
inst = self.cls(self.word_size, index=num, **self.kwargs)
poker = BitPoker.new_with_gfile(self.gfile, self.offset + (self.entsize * num))
inst.read_from_poker(poker)
return inst
def __len__(self):
return self.number
class ElfFileProgramHeaderContainer(ElfFileContainer):
def __str__(self):
f = StringIO.StringIO()
f.write("Program Headers:\n")
format_str = " %-15s%-9s%-11s%-11s%-8s%-8s%-4s%s\n"
f.write(format_str % ("Type", "Offset", "VirtAddr",
"PhysAddr", "FileSiz", "MemSiz", "Flg", "Align"))
for header in self:
x = header.ai
f.write(format_str % (x.p_type, x.p_offset, x.p_vaddr,
x.p_paddr, x.p_filesz, x.p_memsz, x.p_flags, x.p_align))
return f.getvalue()
class ElfFileSectionHeaderContainer(ElfFileContainer):
def __str__(self):
f = StringIO.StringIO()
f.write("There are %d section headers, starting at offset 0x%x:\n\n" % (len(self), self.kwargs["elffile"].header.ai.e_shoff.get()))
f.write("Section Headers:\n")
format_str = " [%2s] %-17.17s %-15s %-8s %-6s %-6s %2s %3s %2s %-3s %-2s\n"
f.write(format_str % ("Nr", "Name", "Type", "Addr", "Off", "Size",
"ES", "Flg", "Lk", "Inf", "Al"))
for idx, header in enumerate(self):
x = header.ai
f.write(format_str % (idx, x.sh_name, x.sh_type, x.sh_addr,
x.sh_offset, x.sh_size, x.sh_entsize,
x.sh_flags, x.sh_link, x.sh_info,
x.sh_addralign))
return f.getvalue()
class ElfFileStringTable(object):
def __init__(self, gfile, section_header):
file_offset = section_header.ai.sh_offset
self.poker = BitPoker.new_with_gfile(gfile, file_offset)
def read(self, offset):
return self.poker.read_c_string(offset)
class Symbols(AIStruct):
def __init__(self, *args, **kwargs):
AIStruct.__init__(self, AIStruct.SIZE32)
self.section = kwargs["section"]
self.setup(
('UINT32', 'st_name', {"format" : self.section.get_sym_name}),
('UINT32', 'value'),
('UINT32', 'size'),
('UINT8', 'info'),
('UINT8', 'other'),
('UINT16', 'st_shndx')
)
def __str__(self):
return "[%s] 0x%08x %5d %3d" % \
(self.ai.st_name, self.ai.value.get(),
self.ai.size.get(), self.ai.st_shndx.get())
class ElfFileSymbolTable(object):
def __init__(self, gfile, section_header):
self.header = section_header
file_offset = section_header.ai.sh_offset
self.poker = BitPoker.new_with_gfile(gfile, file_offset)
def get_symbols(self, section_num = None):
if section_num:
return [ sym for sym in self.header.container(Symbols) if sym.ai.st_shndx.get() == section_num]
else:
return self.header.container(Symbols)
class ElfFile(object):
WORD_SIZE_MAP = {Elf32Header.EI_CLASS_32: Elf32Header.SIZE32,
Elf32Header.EI_CLASS_64: Elf32Header.SIZE64}
BYTE_ORDER_MAP = {Elf32Header.EI_DATA_LSB: 'lsb',
Elf32Header.EI_DATA_MSB: 'msb'}
HEADER_MAP = {Elf32Header.SIZE32: Elf32Header, Elf64Header.SIZE64: Elf64Header}
PROGRAM_HEADER_MAP = {Elf32Header.SIZE32: Elf32ProgramHeader, Elf64Header.SIZE64: Elf64ProgramHeader}
SECTION_HEADER_MAP = {Elf32Header.SIZE32: Elf32SectionHeader, Elf64Header.SIZE64: Elf64SectionHeader}
""" Python representation of an Elf file. """
def __init__(self, gfile, byte_ordering, word_size):
self.gfile = gfile
self.gfile.set_byte_ordering(byte_ordering)
self.byte_order = byte_ordering
self.word_size = word_size
self.header = ElfFile.HEADER_MAP[self.word_size]()
self.header.read_from_poker(BitPoker.new_with_gfile(self.gfile, 0))
# Setup the parts of the file
# ... program headers
self.pheaders = ElfFileProgramHeaderContainer \
(gfile, word_size, self.header.ai.e_phoff, self.header.ai.e_phentsize,
self.header.ai.e_phnum.get(), ElfFile.PROGRAM_HEADER_MAP[word_size], elffile=self)
# ... section headers
self.sheaders = ElfFileSectionHeaderContainer \
(gfile, word_size, self.header.ai.e_shoff, self.header.ai.e_shentsize,
self.header.ai.e_shnum.get(), ElfFile.SECTION_HEADER_MAP[word_size], elffile=self)
# ... string table
if self.header.ai.e_shstrndx != 0:
self.string_table = ElfFileStringTable \
(self.gfile, self.sheaders[self.header.ai.e_shstrndx])
# ... symbol table
self.symtable = None
for header in self.sheaders:
if header.get_name() == ".symtab":
self.symtable = ElfFileSymbolTable(self.gfile, header)
def set_source(self, poker):
self.source_poker = poker
def get_name(self, idx):
return self.string_table.read(idx)
def print_info(self):
print "* Information for ELF file:"
print "* Header info:"
self.header.print_info()
def write_file(selfm, filename):
# Write out head
print "Wirintg out", filename
def from_file(filename):
gfile = GFile.existing(filename)
poker = BitPoker()
poker.set_mmapfile(gfile.mapping, 0) # Offset of 0 from start of file.
poker.set_byte_ordering('lsb') # Use default because we don't (yet) know
header = Elf32Header() # Once again, use a default size.
header.read_from_poker(poker)
# Examine the header for info we need.
# Check the magic first. If we don't and the file is non-ELF, chances are
# class & data won't match which will result in a confusing error message
if header.ai.ei_magic != Elf32Header.EI_MAGIC:
raise ElfFileNotElfException("Wanted magic %r, got %r" \
% (Elf32Header.EI_MAGIC, header.ai.ei_magic))
word_size = ElfFile.WORD_SIZE_MAP[header.ai.ei_class.get()]
byte_order = ElfFile.BYTE_ORDER_MAP[header.ai.ei_data.get()]
return ElfFile(gfile, byte_order, word_size)
from_file = staticmethod(from_file)
def test():
"Test suite"
elf_file = ElfFile.from_file("a.out")
# Check can load an elf
success = 1
try:
x = ElfFile.from_file("a.out")
except:
success = 0
assert success
# CHeck can't load not and elf
success = 0
try:
x = ElfFile.from_file("pyelf.py")
except:
success = 1
assert success
def main():
filename = sys.argv[1] # Consider this a usage message :)
elf_file = ElfFile.from_file(filename)
elf_file.print_info()
if __name__ == '__main__':
if sys.argv[1] != "test":
main()
else:
test()

BIN
tools/pyelf/elf.pyc Normal file

Binary file not shown.

77
tools/pyelf/lmamove.py Executable file
View File

@@ -0,0 +1,77 @@
#!/usr/bin/python
import re, elf, sys, os
from optparse import OptionParser
toolprefix = "arm-none-linux-gnueabi-"
objdump = toolprefix + "objdump"
objcopy = toolprefix + "objcopy"
readelf = toolprefix + "readelf"
egrep = "egrep"
snames_file = "section_names.txt"
def get_section_names(path):
rest, filename = os.path.split(path)
sections = []
os.system(readelf + " -l " + path + " > readelf.out")
os.system(egrep + r' "(\.){1}(\w){1}" ' + " readelf.out > sections.out")
for line in file('sections.out'):
secnum, secname = str.split(line)
sections.append((secnum,secname))
print "Sections:\n" + str(sections)
return sections
helpmsg = \
'''Usage:
lmamove.py <filename> <[<op>]offset>
Where <filename> is the file to modify, <offset> is the offset to be added,
subtracted or assigned, depending on the <op>, which can be either + or -
!!! NOTE THIS TOOL IS NOT VERY USEFUL BECAUSE IT TURNS OUT THAT SOME SECTIONS
ARE LIKELY TO BE PUT TOGETHER INTO THE SAME SEGMENT. For example (.text with .rodata)
and (.data with .bss) Therefore moving one sectoin's LMA confuses what to do with the
other section. The segment layout is almost always not same as initial after LMA
modification with objcopy. !!!
'''
def check_args():
if len(sys.argv) < 3:
print helpmsg
sys.exit()
filename = sys.argv[1]
if not os.path.exists(filename):
print "Given path: " + filename + " does not exist.\n"
sys.exit()
def move_sections(path, sections, op, offset):
for secnum, secname in sections:
os.system(objcopy + " --change-section-lma " + secname + op + offset + " " + path)
def lmamove():
'''
Moves an ARM ELF executable's LMA by moving each of its sections by
the given offset. It uses binutils (namely readelf and objcopy) to do
the actual work. Normally objcopy supports a similar operation; moving
of VMA of the whole program by --adjust-vma switch. But it only supports
modifying LMAs by section. Therefore this script extracts all loadable
section names and moves them one by one in order to move the whole program.
'''
check_args()
filename = sys.argv[1]
offset = sys.argv[2]
if offset[0] in "+-":
op = offset[0]
offset = offset[1:]
else:
op = "+"
if offset[:1] == "0x":
offset = int(offset, 16)
section_names = get_section_names(filename)
move_sections(filename, section_names, op, offset)
print("Done.\n")
if __name__ == "__main__":
lmamove()

10
tools/pyelf/package.cfg Normal file
View File

@@ -0,0 +1,10 @@
[info]
Author: Ben Leslie
Name: PyELF
Copyright: NICTA
Licence: OzPLB
Description: PyELF library allows the parsing and manipulation
of ELF objects in a platform and toolchain independant manner.
It is primarily designed for the Kenge build system, but would
form a great basis for a general purpose Python ELF library.
Category: tool

45
tools/pyelf/pyelf.py Normal file
View File

@@ -0,0 +1,45 @@
import mmap
import os
class ELF:
EI_MAGIC = "\x7fELF"
def __init__(self, name):
f = file(name, "rb")
size = os.stat(name).st_size
self.data = mmap.mmap(f.fileno(), size, mmap.MAP_PRIVATE, mmap.PROT_READ)
if self.magic != self.EI_MAGIC:
raise "Not an elf"
def get_magic(self):
return self.data[:4]
magic = property(get_magic)
def get_class(self):
return self.data[4]
elf_class = property(get_class)
"Test suite"
x = ELF("a.out")
# Check can load an elf
success = 1
try:
x = ELF("a.out")
except:
success = 0
assert success
# CHeck can't load not and elf
success = 0
try:
x = ELF("pyelf.py")
except:
success = 1
assert success

120
tools/pyelf/readelf.py Executable file
View File

@@ -0,0 +1,120 @@
#!/usr/bin/env python
from aistruct import AIStruct
import elf, sys
from optparse import OptionParser
from os import path
class AfterBurner(AIStruct):
def __init__(self, *args, **kwargs):
AIStruct.__init__(self, AIStruct.SIZE32)
self.setup(
('UINT32', 'addr')
)
def __str__(self):
return "0x%x" % self.ai.addr.get()
def main():
parser = OptionParser(add_help_option=False)
parser.add_option("-h", "--file-header",
action="store_true", dest="header", default=False,
help="Display the ELF file header")
parser.add_option("-l", "--program-headers",
action="store_true", dest="program_headers", default=False,
help="Display the program headers")
parser.add_option("-S", "--section-headers",
action="store_true", dest="section_headers", default=False,
help="Display the section headers")
parser.add_option("--afterburn",
action="store_true", dest="afterburn", default=False,
help="Display the afterburn relocations")
parser.add_option("--first-free-page",
action="store_true", dest="ffpage", default=False,
help="Prints out (in .lds format) the address of the first free physical" + \
"page after this image at load time. Using this information at link" + \
"time, images can be compiled and linked consecutively and loaded in" + \
"consecutive memory regions at load time.")
parser.add_option("--lma-start-end", action="store_true", dest="lma_boundary", default=False,
help="Prints out the start and end LMA boundaries of an image." + \
"This is useful for autogenerating a structure for the microkernel" + \
"to discover at run-time where svc tasks are loaded.")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.print_help()
return
elffile = elf.ElfFile.from_file(args[0])
if options.header:
print elffile.header
if options.program_headers:
print elffile.pheaders
if options.section_headers:
print elffile.sheaders
if options.afterburn:
burnheader = elffile.sheaders[".afterburn"]
burns = burnheader.container(AfterBurner)
print "There are %d afterburn entry points" % len(burns)
print "Afterburn:"
for burn in burns:
print " ", burn
if options.lma_boundary:
paddr_first = 0
paddr_start = 0
paddr_end = 0
for pheader in elffile.pheaders:
x = pheader.ai
if str(x.p_type) != "LOAD":
continue
# First time assign the first p_paddr.
if paddr_first == 0:
paddr_first = 1
paddr_start = x.p_paddr.value
# Then if new paddr is lesser, reassign start.
if paddr_start > x.p_paddr.value:
paddr_start = x.p_paddr.value
# If end of segment is greater, reassign end.
if paddr_end < x.p_paddr + x.p_memsz:
paddr_end = x.p_paddr + x.p_memsz
rest, image_name = path.split(args[0])
if image_name[-4] == ".":
image_name = image_name[:-4]
print image_name
print "image_start " + hex(paddr_start)[:-1]
print "image_end " + hex(paddr_end)[:-1]
if options.ffpage:
paddr_max = 0
p_align = 0
for pheader in elffile.pheaders:
x = pheader.ai
if str(x.p_type) == "LOAD":
paddr = x.p_paddr + x.p_memsz
p_align = x.p_align
if paddr > paddr_max:
paddr_max = paddr
print "/*\n" + \
" * The next free p_align'ed LMA base address\n" + \
" *\n" + \
" * p_align = " + hex(p_align.value) + "\n" + \
" *\n" + \
" * Recap from ELF spec: p_align: Loadable process segments must have\n" + \
" * congruent values for p_vaddr and p_offset, modulo the page size. \n" + \
" * This member gives the value to which the segments are aligned in \n" + \
" * memory and in the file. Values 0 and 1 mean that no alignment is \n" + \
" * required. Otherwise, p_align should be a positive, integral power\n" + \
" * of 2, and p_addr should equal p_offset, modulo p_align. \n" + \
" * This essentially means next available address must be aligned at\n" + \
" * p_align, rather than the page_size, which one (well, I) would \n" + \
" * normally expect. \n" + \
" */\n"
paddr_aligned = paddr_max & ~(p_align.value - 1)
if paddr_max & (p_align.value - 1):
paddr_aligned += p_align.value
print "physical_base = " + hex(paddr_aligned)[:-1] + ";"
if __name__ == "__main__":
main()

17
tools/tagsgen/tagsgen_all Executable file
View File

@@ -0,0 +1,17 @@
rm -f cscope.*
rm -f tags
# Put all sources into a file list.
find ./ -name '*.cc' > tagfilelist
find ./ -name '*.c' >> tagfilelist
find ./ -name '*.h' >> tagfilelist
find ./ -name '*.s' >> tagfilelist
find ./ -name '*.S' >> tagfilelist
find ./ -name '*.lds' >> tagfilelist
# Use file list to include in tags.
ctags --languages=C,C++,Asm --recurse -Ltagfilelist
cscope -q -k -R -i tagfilelist
# Remove file list.
rm -f tagfilelist

22
tools/tagsgen/tagsgen_kernel Executable file
View File

@@ -0,0 +1,22 @@
rm -f cscope.*
rm -f tags
# Put all sources into a file list.
find ./src -name '*.cc' > tagfilelist
find ./src -name '*.c' >> tagfilelist
find ./src -name '*.h' >> tagfilelist
find ./src -name '*.s' >> tagfilelist
find ./src -name '*.S' >> tagfilelist
find ./src -name '*.lds' >> tagfilelist
find ./include -name '*.h' >> tagfilelist
find ./include -name '*.s' >> tagfilelist
find ./include -name '*.S' >> tagfilelist
find ./include -name '*.lds' >> tagfilelist
# Use file list to include in tags.
ctags --languages=C,Asm --recurse -Ltagfilelist
cscope -q -k -R -i tagfilelist
# Remove file list.
rm -f tagfilelist

20
tools/tagsgen/tagsgen_loader Executable file
View File

@@ -0,0 +1,20 @@
# Put all sources into a file list.
find ./loader -name '*.cc' > tagfilelist
find ./loader -name '*.c' >> tagfilelist
find ./loader -name '*.h' >> tagfilelist
find ./loader -name '*.s' >> tagfilelist
find ./loader -name '*.S' >> tagfilelist
find ./libs -name '*.cc'>> tagfilelist
find ./libs -name '*.c' >> tagfilelist
find ./libs -name '*.h' >> tagfilelist
find ./libs -name '*.s' >> tagfilelist
find ./libs -name '*.S' >> tagfilelist
# Use file list to include in tags.
exuberant-ctags --languages=C,Asm --recurse -Ltagfilelist
cscope -q -k -R -i tagfilelist
# Remove file list.
#rm -f tagfilelist