Hi all,
Having been looking at the OpenBIOS Sparc implementation recently, I came across the following interesting reproducible test case with latest SVN of Qemu and openbios:
./qemu-system-sparc -nographic -serial stdio
Configuration device id QEMU version 1 machine id 32 UUID: 00000000-0000-0000-0000-000000000000 CPUs: 1 x FMI,MB86904 Welcome to OpenBIOS v1.0RC1 built on Jan 24 2009 10:08 Type 'help' for detailed information
[sparc] Booting file 'disk' with parameters '' Trying disk (disk) Trying disk:d (disk:d) Unsupported image format
0 > see see : see ' (see) ; ok 0 > see test-all : test-all active-package cr (lit) (lit) then Unhandled Exception 0x00000009 PC = 0xffd066c4 NPC = 0xffd066c8 Stopping execution
Similarly I see the same error in get-package-path too:
0 > see get-package-path : get-package-path ?dup 0= if 0 0 dup >dn.parent @ 0= if drop (lit) (lit) then Unhandled Exception 0x00000009 PC = 0xffd066c4 NPC = 0xffd066c8 Stopping execution
AFAICT the problem is related to the occurence of string constants like "foo" or "bar" in the source code. Does anyone else see this on other platforms? I suspect given that forth is interpreted that this is a lower-level issue of some kind...
ATB,
Mark.
Mark Cave-Ayland wrote:
AFAICT the problem is related to the occurence of string constants like "foo" or "bar" in the source code. Does anyone else see this on other platforms? I suspect given that forth is interpreted that this is a lower-level issue of some kind...
Actually I think this is an OpenBIOS bug: when I try the same command on qemu-system-x86_64 it crashes there too :(
ATB,
Mark.
On 24.01.2009 15:22 Uhr, Mark Cave-Ayland wrote:
Mark Cave-Ayland wrote:
AFAICT the problem is related to the occurence of string constants like "foo" or "bar" in the source code. Does anyone else see this on other platforms? I suspect given that forth is interpreted that this is a lower-level issue of some kind...
Actually I think this is an OpenBIOS bug: when I try the same command on qemu-system-x86_64 it crashes there too :(
See patch.. There seems to be another oddity in " which caused me to use s" instead of " in nvram.fs... Who finds the remaining problem? ;-)
Stefan
Stefan Reinauer wrote:
[...] See patch.. There seems to be another oddity in " which caused me to use s" instead of " in nvram.fs... Who finds the remaining problem? ;-)
What's the distinction between s" and " ?
One of the persistent problems we run into at Sun (in particular relating to NVRAM and properties being passed to Solaris) is the dichotomy between counted strings and null-terminated strings. A string constant ( " ) is a counted string, but supposedly with a terminating null outside the count, which ensures that any C-code doesn't barf on being passed a pointer to the string. The problem often arises when string constants are copied, which doesn't necessarily bring along the null terminator - passing such a copied string can cause problems in careless C code.
An example I recall was code in Solaris' consconfig.c which would complain when it didn't like the values it found in ttya-mode. It would print out an error message using sprintf's %s to reference the property, and that could run off the end of the universe. Another example was in comparisons for property values, where sometimes a string value for a property /included/ a terminating null byte (depending on how the property was created) and sometimes didn't - which could cause problems in not being able to match values.
Stefan Reinauer wrote:
See patch.. There seems to be another oddity in " which caused me to use s" instead of " in nvram.fs... Who finds the remaining problem? ;-)
Stefan
Hi Stefan,
Thanks for the patch! With the patch applied, then "see" no longer crashes on those particular routines. Interestingly enough, digging further into the BIOS I still see some discrepancies between the source code and the detokenized version:
0 > see find-device : find-device 2dup " .." strcmp 0= if 2drop active-package dup if >dn.parent @ dup 0= if (lit) throw active-package! exit 0 -rot path-resolution 0= if false exit active-package swap true path-res-cleanup active-package!
In this case, (lit) should be "..". And also:
0 > see (find-dev) : (find-dev) active-package -rot (lit) catch if 3drop false exit active-package swap active-package! true ; ok
And here (lit) should be "[']". Am I right in thinking that it should be possible to reconstruct any source exactly (minus formatting) from a tokenized input?
Many thanks,
Mark.
Mark Cave-Ayland wrote:
Thanks for the patch! With the patch applied, then "see" no longer crashes on those particular routines. Interestingly enough, digging further into the BIOS I still see some discrepancies between the source code and the detokenized version:
0 > see find-device : find-device 2dup " .." strcmp 0= if 2drop active-package dup if >dn.parent @ dup 0= if (lit) throw active-package! exit 0 -rot path-resolution 0= if false exit active-package swap true path-res-cleanup active-package!
In this case, (lit) should be "..". And also:
-22 even.
And all the "then"s are missing. That's a bit more complicated to implement though.
0 > see (find-dev) : (find-dev) active-package -rot (lit) catch if 3drop false exit active-package swap active-package! true ; ok
And here (lit) should be "[']".
Hm..
Am I right in thinking that it should be possible to reconstruct any source exactly (minus formatting) from a tokenized input?
Not exactly.
Forgive me for some nit-picking, the forth dictionary is not "tokenized" forth code, like the stuff toke produces. A tokenizer just produces a binary representation of the source code ("FCode"), similar to what some BASIC dialects did in ancient times to reduce file size. It's still "source code" and in order to execute it, it still needs to be "compiled", just like forth source code.
Now, if source code (or FCode for that matter) is compiled, the forth engine can keep things simple.
Example:
: some-new-word ( -- xt-of-find-device ) ['] find-device ;
['] and ' will put the execution token (xt) of a word on the stack. That execution token could then be executed with "execute". It's like a function pointer in C.
['] is executed as an immediate word, which means it will not start looking for "find-device" when some-new-word is executed, but rather when it is "compiled into the dictionary" (aka when it is defined).
So at the time some-new-word is executed, all it really does is put a cell sized integer on the stack. Just as if you had typed -22.
The primitive word to achieve this is (lit). When a (lit) is executed, it will read the cell after the execution token of (lit) and put it to the stack. It has no knowledge anymore about what number that would be.
So when a number is compiled into the dictionary, it looks like this:
| xt-of-(lit) | number | next-word's-xt | ...
Formerly, when a string was put on the stack with " it looked like this:
| xt-of-(lit) | pointer-to-string | xt-of-(lit) | length-of-string | xt-of-dobranch | offset-behind-string | cell-aligned-string | ...
So it's not easy to recognize from two (lit) and a dobranch that the above is a string. Which is why at some point we started hiding that magic behind another word called (") which basically puts a two numbers on the stack, but is only used for string handling. So we can recognize strings in see. For some odd reason s" was using (") but " was not.
We can do this kind of thing for other words, too, in order to improve the reversability of forth words. Suggestions, and patches are most welcome!
Stefan