rod file viewer for easier debugging of rod files

This commit is contained in:
Araq 2013-04-04 13:05:38 +02:00
commit beb13ecf62
8 changed files with 303 additions and 21 deletions

View file

@ -18,5 +18,5 @@ const
VersionPatch* = 1 VersionPatch* = 1
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
RodFileVersion* = "1210" # modify this if the rod-format changes! RodFileVersion* = "1211" # modify this if the rod-format changes!

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2013 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -126,7 +126,7 @@ type
s: cstring # mmap'ed file contents s: cstring # mmap'ed file contents
options: TOptions options: TOptions
reason: TReasonForRecompile reason: TReasonForRecompile
modDeps: seq[int32] modDeps: TStringSeq
files: TStringSeq files: TStringSeq
dataIdx: int # offset of start of data section dataIdx: int # offset of start of data section
convertersIdx: int # offset of start of converters section convertersIdx: int # offset of start of converters section
@ -384,8 +384,14 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
result.id = id result.id = id
IdTablePut(r.syms, result, result) IdTablePut(r.syms, result, result)
if debugIds: registerID(result) if debugIds: registerID(result)
elif (result.id != id): elif result.id != id:
InternalError(info, "decodeSym: wrong id") InternalError(info, "decodeSym: wrong id")
elif result.kind != skStub:
# we already loaded the symbol
return
else:
reset(result[])
result.id = id
result.kind = k result.kind = k
result.name = ident # read the rest of the symbol description: result.name = ident # read the rest of the symbol description:
if r.s[r.pos] == '^': if r.s[r.pos] == '^':
@ -498,7 +504,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
IdTablePut(r.syms, s, s) IdTablePut(r.syms, s, s)
StrTableAdd(rodCompilerProcs, s) StrTableAdd(rodCompilerProcs, s)
proc processIndex(r: PRodReader, idx: var TIndex) = proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
var key, val, tmp: int var key, val, tmp: int
inc(r.pos, 2) # skip "(\10" inc(r.pos, 2) # skip "(\10"
inc(r.line) inc(r.line)
@ -512,6 +518,7 @@ proc processIndex(r: PRodReader, idx: var TIndex) =
key = idx.lastIdxKey + 1 key = idx.lastIdxKey + 1
val = tmp + idx.lastIdxVal val = tmp + idx.lastIdxVal
IITablePut(idx.tab, key, val) IITablePut(idx.tab, key, val)
if not outf.isNil: outf.write(key, " ", val, "\n")
idx.lastIdxKey = key idx.lastIdxKey = key
idx.lastIdxVal = val idx.lastIdxVal = val
setID(key) # ensure that this id will not be used setID(key) # ensure that this id will not be used
@ -602,7 +609,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
of "DEPS": of "DEPS":
inc(r.pos) # skip ':' inc(r.pos) # skip ':'
while r.s[r.pos] > '\x0A': while r.s[r.pos] > '\x0A':
r.modDeps.add int32(decodeVInt(r.s, r.pos)) r.modDeps.add(r.files[int32(decodeVInt(r.s, r.pos))])
if r.s[r.pos] == ' ': inc(r.pos) if r.s[r.pos] == ' ': inc(r.pos)
of "INTERF": of "INTERF":
r.interfIdx = r.pos + 2 r.interfIdx = r.pos + 2
@ -673,11 +680,9 @@ proc newRodReader(modfilename: string, crc: TCrc32,
add(version, r.s[r.pos]) add(version, r.s[r.pos])
inc(r.pos) inc(r.pos)
if r.s[r.pos] == '\x0A': inc(r.pos) if r.s[r.pos] == '\x0A': inc(r.pos)
if version == RodFileVersion: if version != RodFileVersion:
# since ROD files are only for caching, no backwards compatibility is # since ROD files are only for caching, no backwards compatibility is
# needed # needed
processRodFile(r, crc)
else:
result = nil result = nil
else: else:
result = nil result = nil
@ -813,6 +818,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
if r == nil: if r == nil:
result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist) result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
else: else:
processRodFile(r, crc)
result = r.reason result = r.reason
if result == rrNone: if result == rrNone:
# check modules it depends on # check modules it depends on
@ -822,7 +828,7 @@ proc checkDep(fileIdx: int32): TReasonForRecompile =
var res = checkDep(SystemFileIdx) var res = checkDep(SystemFileIdx)
if res != rrNone: result = rrModDeps if res != rrNone: result = rrModDeps
for i in countup(0, high(r.modDeps)): for i in countup(0, high(r.modDeps)):
res = checkDep(r.modDeps[i]) res = checkDep(r.modDeps[i].fileInfoIdx)
if res != rrNone: if res != rrNone:
result = rrModDeps result = rrModDeps
# we cannot break here, because of side-effects of `checkDep` # we cannot break here, because of side-effects of `checkDep`
@ -863,6 +869,8 @@ proc rawLoadStub(s: PSym) =
if d == invalidKey: InternalError("loadStub: invalid key") if d == invalidKey: InternalError("loadStub: invalid key")
var rs = decodeSymSafePos(rd, d, UnknownLineInfo()) var rs = decodeSymSafePos(rd, d, UnknownLineInfo())
if rs != s: if rs != s:
#echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
# "\ns: ", toHex(cast[int](s.position), int.sizeof * 2)
InternalError(rs.info, "loadStub: wrong symbol") InternalError(rs.info, "loadStub: wrong symbol")
elif rs.id != theId: elif rs.id != theId:
InternalError(rs.info, "loadStub: wrong ID") InternalError(rs.info, "loadStub: wrong ID")
@ -897,3 +905,263 @@ proc getBody*(s: PSym): PNode =
InitIdTable(gTypeTable) InitIdTable(gTypeTable)
InitStrTable(rodCompilerProcs) InitStrTable(rodCompilerProcs)
# viewer:
proc writeNode(f: TFile; n: PNode) =
f.write("(")
if n != nil:
f.write($n.kind)
if n.typ != nil:
f.write('^')
f.write(n.typ.id)
case n.kind
of nkCharLit..nkInt64Lit:
if n.intVal != 0:
f.write('!')
f.write(n.intVal)
of nkFloatLit..nkFloat64Lit:
if n.floatVal != 0.0:
f.write('!')
f.write($n.floatVal)
of nkStrLit..nkTripleStrLit:
if n.strVal != "":
f.write('!')
f.write(n.strVal.escape)
of nkIdent:
f.write('!')
f.write(n.ident.s)
of nkSym:
f.write('!')
f.write(n.sym.id)
else:
for i in countup(0, sonsLen(n) - 1):
writeNode(f, n.sons[i])
f.write(")")
proc writeSym(f: TFile; s: PSym) =
if s == nil:
f.write("{}\n")
return
f.write("{")
f.write($s.kind)
f.write('+')
f.write(s.id)
f.write('&')
f.write(s.name.s)
if s.typ != nil:
f.write('^')
f.write(s.typ.id)
if s.owner != nil:
f.write('*')
f.write(s.owner.id)
if s.flags != {}:
f.write('$')
f.write($s.flags)
if s.magic != mNone:
f.write('@')
f.write($s.magic)
if s.options != gOptions:
f.write('!')
f.write($s.options)
if s.position != 0:
f.write('%')
f.write($s.position)
if s.offset != -1:
f.write('`')
f.write($s.offset)
if s.constraint != nil:
f.write('#')
f.writeNode(s.constraint)
if s.ast != nil:
f.writeNode(s.ast)
f.write("}\n")
proc writeType(f: TFile; t: PType) =
if t == nil:
f.write("[]\n")
return
f.write('[')
f.write($t.kind)
f.write('+')
f.write($t.id)
if t.n != nil:
f.writeNode(t.n)
if t.flags != {}:
f.write('$')
f.write($t.flags)
if t.callConv != low(t.callConv):
f.write('?')
f.write($t.callConv)
if t.owner != nil:
f.write('*')
f.write($t.owner.id)
if t.sym != nil:
f.write('&')
f.write(t.sym.id)
if t.size != -1:
f.write('/')
f.write($t.size)
if t.align != 2:
f.write('=')
f.write($t.align)
if t.containerID != 0:
f.write('@')
f.write($t.containerID)
for i in countup(0, sonsLen(t) - 1):
if t.sons[i] == nil:
f.write("^()")
else:
f.write('^')
f.write($t.sons[i].id)
f.write("]\n")
proc viewFile(rodfile: string) =
var r = newRodReader(rodfile, 0, 0)
if r == nil:
rawMessage(errGenerated, "cannot open file (or maybe wrong version):" &
rodfile)
return
var outf = system.open(rodfile.changeFileExt(".rod.txt"), fmWrite)
while r.s[r.pos] != '\0':
let section = rdWord(r)
case section
of "CRC":
inc(r.pos) # skip ':'
outf.writeln("CRC:", $decodeVInt(r.s, r.pos))
of "ID":
inc(r.pos) # skip ':'
r.moduleID = decodeVInt(r.s, r.pos)
setID(r.moduleID)
outf.writeln("ID:", $r.moduleID)
of "OPTIONS":
inc(r.pos) # skip ':'
r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
outf.writeln("OPTIONS:", $r.options)
of "GOPTIONS":
inc(r.pos) # skip ':'
let dep = cast[TGlobalOptions](int32(decodeVInt(r.s, r.pos)))
outf.writeln("GOPTIONS:", $dep)
of "CMD":
inc(r.pos) # skip ':'
let dep = cast[TCommands](int32(decodeVInt(r.s, r.pos)))
outf.writeln("CMD:", $dep)
of "DEFINES":
inc(r.pos) # skip ':'
var d = 0
outf.write("DEFINES:")
while r.s[r.pos] > '\x0A':
let w = decodeStr(r.s, r.pos)
inc(d)
outf.write(" ", w)
if r.s[r.pos] == ' ': inc(r.pos)
outf.write("\n")
of "FILES":
inc(r.pos, 2) # skip "(\10"
inc(r.line)
outf.write("FILES(\n")
while r.s[r.pos] != ')':
let relativePath = decodeStr(r.s, r.pos)
let resolvedPath = relativePath.findModule
let rr = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(rr)
inc(r.pos) # skip #10
inc(r.line)
outf.writeln(rr)
if r.s[r.pos] == ')': inc(r.pos)
outf.write(")\n")
of "INCLUDES":
inc(r.pos, 2) # skip "(\10"
inc(r.line)
outf.write("INCLUDES(\n")
while r.s[r.pos] != ')':
let w = r.files[decodeVInt(r.s, r.pos)]
inc(r.pos) # skip ' '
let inclCrc = decodeVInt(r.s, r.pos)
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
outf.write(w, " ", inclCrc, "\n")
if r.s[r.pos] == ')': inc(r.pos)
outf.write(")\n")
of "DEPS":
inc(r.pos) # skip ':'
outf.write("DEPS:")
while r.s[r.pos] > '\x0A':
let v = int32(decodeVInt(r.s, r.pos))
r.modDeps.add(r.files[v])
if r.s[r.pos] == ' ': inc(r.pos)
outf.write(" ", r.files[v])
outf.write("\n")
of "INTERF", "COMPILERPROCS":
inc r.pos, 2
if section == "INTERF": r.interfIdx = r.pos
else: r.compilerProcsIdx = r.pos
outf.write(section, "(\n")
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
let w = decodeStr(r.s, r.pos)
inc(r.pos)
let key = decodeVInt(r.s, r.pos)
inc(r.pos) # #10
outf.write(w, " ", key, "\n")
if r.s[r.pos] == ')': inc r.pos
outf.write(")\n")
of "INDEX":
outf.write(section, "(\n")
processIndex(r, r.index, outf)
outf.write(")\n")
of "IMPORTS":
outf.write(section, "(\n")
processIndex(r, r.imports, outf)
outf.write(")\n")
of "CONVERTERS", "METHODS":
inc r.pos
if section == "METHODS": r.methodsIdx = r.pos
else: r.convertersIdx = r.pos
outf.write(section, ":")
while r.s[r.pos] > '\x0A':
let d = decodeVInt(r.s, r.pos)
outf.write(" ", $d)
if r.s[r.pos] == ' ': inc(r.pos)
outf.write("\n")
of "DATA":
inc(r.pos, 2)
r.dataIdx = r.pos
outf.write("DATA(\n")
while r.s[r.pos] != ')':
if r.s[r.pos] == '(':
outf.writeNode decodeNode(r, UnknownLineInfo())
outf.write("\n")
elif r.s[r.pos] == '[':
outf.writeType decodeType(r, UnknownLineInfo())
else:
outf.writeSym decodeSym(r, UnknownLineInfo())
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
if r.s[r.pos] == ')': inc r.pos
outf.write(")\n")
of "INIT":
outf.write("INIT(\n")
inc r.pos, 2
r.initIdx = r.pos
while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')':
let d = decodeVInt(r.s, r.pos)
inc(r.pos) # #10
#let p = r.pos
#r.pos = d + r.dataIdx
#outf.writeNode decodeNode(r, UnknownLineInfo())
#outf.write("\n")
#r.pos = p
if r.s[r.pos] == ')': inc r.pos
outf.write("\n")
else:
InternalError("invalid section: '" & section &
"' at " & $r.line & " in " & r.filename)
skipSection(r)
if r.s[r.pos] == '\x0A':
inc(r.pos)
inc(r.line)
outf.close
when isMainModule:
viewFile(paramStr(1).addFileExt(rodExt))

View file

@ -205,6 +205,9 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
return return
# we need no surrounding [] here because the type is in a line of its own # we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: InternalError("encodeType: tyForward") if t.kind == tyForward: InternalError("encodeType: tyForward")
# for the new rodfile viewer we use a preceeding [ so that the data section
# can easily be disambiguated:
add(result, '[')
encodeVInt(ord(t.kind), result) encodeVInt(ord(t.kind), result)
add(result, '+') add(result, '+')
encodeVInt(t.id, result) encodeVInt(t.id, result)

View file

@ -83,7 +83,7 @@ proc serve*(action: proc (){.nimcall.}) =
new(stdoutSocket) new(stdoutSocket)
while true: while true:
accept(server, stdoutSocket) accept(server, stdoutSocket)
discard stdoutSocket.recvLine(inp) stdoutSocket.readLine(inp)
execute inp.string execute inp.string
stdoutSocket.send("\c\L") stdoutSocket.send("\c\L")
stdoutSocket.close() stdoutSocket.close()

View file

@ -1597,6 +1597,18 @@ proc `$`*[T: tuple|object](x: T): string =
result.add($value) result.add($value)
result.add(")") result.add(")")
proc `$`*[T: set](x: T): string =
## generic ``$`` operator for sets that is lifted from the components
## of `x`. Example:
##
## .. code-block:: nimrod
## ${23, 45} == "{23, 45}"
result = "{"
for value in items(x):
if result.len > 1: result.add(", ")
result.add($value)
result.add("}")
when false: when false:
proc `$`*[T](a: openArray[T]): string = proc `$`*[T](a: openArray[T]): string =
## generic ``$`` operator for open arrays that is lifted from the elements ## generic ``$`` operator for open arrays that is lifted from the elements

View file

@ -30,4 +30,4 @@ for i in 0 .. <10:
echo f.id echo f.id
gc_fullcollect() gc_fullcollect()
echo alive_foos.len <= 2 echo alive_foos.len <= 3

View file

@ -1,5 +1,5 @@
discard """ discard """
line: 49 line: 51
file: "sysio.nim" file: "sysio.nim"
errormsg: "can raise an unlisted exception: ref EIO" errormsg: "can raise an unlisted exception: ref EIO"
""" """

View file

@ -30,7 +30,6 @@ Bugs
- osproc execProcesses can deadlock if all processes fail (as experienced - osproc execProcesses can deadlock if all processes fail (as experienced
in c++ mode) in c++ mode)
- bootstrapping does not work in C++ mode - bootstrapping does not work in C++ mode
- the new m&s GC is still buggy
version 0.9.4 version 0.9.4