How to print out a pointer using printf under xv6? - xv6

I am using xv6 and I want to print out the pointer's address returned from sbrk
I am trying to use:
printf(sbrk(0),"%p\n");
But when I tried to make, it complained:
error: passing argument 1 of ‘printf’ makes integer from pointer without a cast [-Werror=int-conversion]
printf(sbrk(0), "%p\n");
Is there a way to print out a pointer under xv6?
If you want I can share you with the make file - but I just cloned it from the xv6 repo

What about printf(1, "%p\n", sbrk(0));?
The xv6 printf function (from printf.c) need one extra parameter given first: the fd number in which you want to write.

Related

How to convert OCaml signal to POSIX signal or string?

I run a subprocess from an OCaml program and check its termination status. If it exited normally (WEXITED int), I get the expected return code (0 usually indicating success).
However, if it was terminated by a signal (WSIGNALED int), I don't get the proper POSIX signal number. Instead, I get some (negative) OCaml specific signal number.
How do I convert this nonstandard signal number to a proper POSIX signal number, for proper error reports? Alternatively, how do I convert this number to a string?
(I'm aware that there are tons of named integer values like Sys.sigabrt, but do I really have to write that large match statement myself? Moreover, I don't get why they didn't use a proper variant type in the first place, given that those signal numbers are OCaml specific anyway.)
There is a function in the OCaml runtime that does this conversion (naturally). It is not kosher to call this function, but if you don't mind writing code that can break in future releases of OCaml (and other possibly bad outcomes), here is code that works for me:
A wrapper for the OCaml runtime function:
$ cat wrap.c
#include <caml/mlvalues.h>
extern int caml_convert_signal_number(int);
value oc_sig_to_host_sig(value ocsignum)
{
/* Convert a signal number from OCaml to host system.
*/
return Val_int(caml_convert_signal_number(Int_val(ocsignum)));
}
A test program.
$ cat m.ml
external convert : int -> int = "oc_sig_to_host_sig"
let main () =
Printf.printf "converted %d -> %d\n" Sys.sigint (convert Sys.sigint)
let () = main ()
Compile the program and try it out:
$ ocamlopt -o m -I $(ocamlopt -where) wrap.c m.ml
$ ./m
converted -6 -> 2
All in all, it might be better just to write some code that compares against the different signals defined in the Sys module and translates them to strings.

read the latest line of a serial port

I haven't ever written any code in tcl and pretty novice on serial communication, so sorry in advance if my question doesn't make sense.
I'm trying to solve this problem where I want to listen to a serial port and print the updates line by line in SciLab like a normal serial terminal (e.g. Arduino's serial monitor). The Serial Communication Toolbox for Scilab has a readserial macro (source on GitHub):
function buf=readserial(h,n)
if ~exists("n","local") then
N=serialstatus(h); n=N(1)
end
TCL_EvalStr("binary scan [read "+h+" "+string(n)+"] cu* ttybuf")
buf=ascii(evstr(TCL_GetVar("ttybuf")));
endfunction
where the TCL_EvalStr interprets a string in tcl. So my questin is how I can change the line:
binary scan [read "+h+" "+string(n)+"] cu* ttybuf
so it only returns the latest non-empty line on the serial port? I would also appreciate if you could eli5 what this line does?
P.S.1. So far from here I tried:
TCL_EvalStr("binary scan [lindex [split [read -nonewline "+h+" "+string(n)+"] "\n"] end] cu* ttybuf")
but I get the error message:
Error: syntax error, unexpected string, expecting "," or )
In SciLab.
P.S.2. Defining a new function:
function buf=readlnserial(h)
TCL_EvalStr("binary scan [lindex [split [read -nonewline "+h+"] \"\n\"] end] cu* ttybuf")
buf=ascii(evstr(TCL_GetVar("ttybuf")));
endfunction
leads to error message:
Undefined operation for the given operands.
check or define function %c_l_s for overloading.
In SciLab terminal.
P.S.3. Commands:
TCL_EvalStr('[split [read -nonewline '+h+'] "\n"]')
or
TCL_EvalStr("[split [read -nonewline "+h+"] '\n']")
both lead to error:
Error: Heterogeneous string detected, starting with ' and ending with ".
In SciLab.
P.S.4. I think if I use the SciLab command TCL_EvalFile instead of TCL_EvalStr I can solve the issue above. I just need to figure out how to pass h to the tcl script and read back ttybuf.
P.S.5. I was able to solve the crazy conflict between SciLab string and "\n" by using curly brackets instead of double quotation:
TCL_EvalStr("binary scan [lindex [split [read -nonewline "+h+"] {\n}] end] cu* ttybuf")
however it is still not giving what I'm lookking for.
P.S.6. For those who end up here due to the heterogeneous strings with quotation or double quotation, the correct syntax is 'this '"string'" is inside quotation'. Basically single quotation before other single quotation or double quotations turn them into literal characters.
First, let's finish taking apart the line:
binary scan [read "+h+" "+string(n)+"] cu* ttybuf
That's really this:
binary scan [read CHANNEL NUM_BYTES] cu* ttybuf
where CHANNEL is really the name of the Tcl channel that you're reading from (which probably ought to be in binary mode but that's out of scope of the code you're showing), and NUM_BYTES is the number of bytes to be read. This is then processed to a list of numbers (written to the Tcl variable ttybuf) which are the unsigned bytes that were read.
Now, you're wanting to use line-oriented reading. Well, Tcl's read command doesn't do that (that's either fixed-buffer or whole-file oriented); you need gets for line-oriented reading. (You never want whole-file oriented processing when reading from a serial line; it never reaches EOF. You can do trickery with non-blocking reads… but that's quite complex.)
The gets command will return the next line read from a channel, with end-of-line marker removed. We can still use it with binary channels (it's a little weird, but not impossible) so that means we can then do:
binary scan [gets CHANNEL] cu* ttybuf
Converting that back through all that wrapper you've got:
function buf=readserialline(h)
TCL_EvalStr("binary scan [gets "+h+"] cu* ttybuf")
buf=ascii(evstr(TCL_GetVar("ttybuf")));
endfunction
I renamed it, and I removed all the manipulation of n; lines are lines, and are not of fixed length. (I wonder whether we can retrieve the string directly without converting through a list of bytes; that would be quite a bit more efficient. But that's secondary to getting this working at all.)
About
Whatever the string is delimited with " or ', inserting any ' or "
in it is done by doubling it.
So +"] '\n']" must be replaced with +"] ''\n'']", and +'] "\n"]' with +'] ""\n""]'

How can I make Modelsim warn me about 'X' signal?

I am working on large design using Modelsim.
I've read about the way modelsim simulation works. I am wondering, is there a way that when modelsim evaluates a signal in the simulation phase and it found it to be a red signal, i.e. 'X', to warn me about it?
Knowing that is impossible to list all the signals of the design and look at them one by one.
Also it's very hard to put assertion command for all signals.
You can use the when command to carry out a desired action when a condition is met. The find command can extract signals from the design hierarchy. Look at the Modelsim command reference documentation to see all of its options. The examine command is used to determine the length of arrays and scalar type signals. This example will not work on record types.
proc whenx {sig action} {
when -label $sig "$sig = [string repeat X [string length [examine $sig]]]" $action
}
foreach s [find signals -r /*] {whenx $s "echo \"$s is an X at \$now\""}
This example does not handle arrays which are only partially X's. While you can use array indices in the when expression to test individual bits, it isn't clear how to determine the bounds of an array programmatically in Modelsim tcl.
You can cancel all when conditions with nowhen *.

How can one really create a process using Unix.create_process in OCaml?

I have tried
let _ = Unix.create_process "ls" [||] Unix.stdin Unix.stdout Unix.stderr
in utop, it will crash the whole thing.
If I write that into a .ml and compile and run, it will crash the terminal and my ubuntu will throw a system error.
But why?
The right way to call it is:
let pid = Unix.create_process "ls" [|"ls"|] Unix.stdin Unix.stdout Unix.stderr
The first element of the array must be the "command" name.
On some systems /bin/ls is a link to some bigger executable that will look at argv.(0) to know how to behave (c.f. Busybox); so you really need to provide that info.
(You see more often that with /usr/bin/vi which is now on many systems a sym-link to vim).
Unix.create_process actually calls fork and the does an execvpe, which itself calls the execv primitive (in the OCaml C implementation of the Unix module).
That function then calls cstringvect (a helper function in the C side of the module implementation), which translates the arg parameters into an array of C string, with last entry set to NULL. However, execve and the like expect by convention (see the execve(2) linux man page) the first entry of that array to be the name of the program:
argv is an array of argument strings passed to the new program. By
convention, the first of these strings should contain the filename
associated with the file being executed.
That first entry (or rather, the copy it receives) can actually be changed by the program receiving these args, and is displayed by ls, top, etc.

Passing arguments to execl

I want to create my own pipeline like in Unix terminal (just to practice). It should take applications to execute in quotes like that:
pipeline "ls -l" "grep" ....
I know that I should use fork(), execl() (exec*) and API to redirect stdin and stdout. But are there any alternatives for execl to execute app with arguments using just one argument which includes application path and arguments? Is there a way not to parse manually ls -l but pass it as one argument to execl?
If you have only a single command line instead of an argument vector, let the shell do the parsing for you:
execl("/bin/sh", "sh", "-c", the_command_line, NULL);
Of course, don't let untrusted remote user input into this command line. But if you are dealing with untrusted remote user input to begin with, you should try to arrange to pass actual a list of isolated arguments to the target application as per normal usage of exec[vl], not a command line.
Realistically, you can only really use execl() when the number of arguments to the command are known at compile time. In a shell, you'll normally use execv() or execvp() instead; these can handle an arbitrary number of arguments to the command to be executed. In theory, you use execv() when the path name of the command is given and execvp() (which does a PATH-based search for the command) when it isn't. However, execvp() handles the 'path given' case, so simply use execvp().
So, for your pipeline command, you'll end up with one child using something equivalent to:
char *args_1[] = { "ls", "-l", 0 };
execvp(args_1[0], args_1);
The other child will end up using something equivalent to:
char *args_2[] = { "grep", "pattern", 0 };
execvp(args_2[0], args_2);
Except, of course, that you'll have created those strings from the command line arguments instead of by initialization as shown. Note that grep requires a pattern to search for.
You've still got plumbing issues to resolve. Make sure you close enough pipe file descriptors. When you dup() or dup2() a pipe to standard input or standard output, you close both the file descriptors from the pipe() function.

Resources