How to debug in Erlang? - debugging

When I run my broadcast server, I got the error report:
=ERROR REPORT==== 14-Feb-2012::16:22:29 ===
Error in process <0.757.0> with exit value: {badarg,[{mymodule1,func1,1}]}
=ERROR REPORT==== 14-Feb-2012::16:22:30 ===
Error in process <0.751.0> with exit value: {function_clause,[{mymodule2, func2,[{#Port<0.2

When debugging an error or crash, it is often useful to see what input and output a certain function gets. The debug utility redbug in the eper repo makes it rather easy
Examples:
%%% Trace a function:
1>redbug:start("lists:sort")
2>lists:sort([3,1,2]).
21:41:00 <{erlang,apply,2}> {lists,sort,[[3,1,2]]}
%%% Trace a module and also get the return value
3>redbug:start("string->return")
4>string:to_upper("foo").
21:41:10 <{erlang,apply,2}> {string,to_upper,["foo"]}
21:41:10 <{erlang,apply,2}> {string,'-to_upper/1-lc$^0/1-0-',["foo"]}
...
21:41:10 <{erlang,apply,2}> {string,to_upper,1} -> "FOO"
So in your code I would for example see what input mymodule1:func1 gets:
1>redbug:start("mymodule1:func1").
2> %% redo the call that caused the crash

function_clause means simply that there is no definition for function mymodule2:func2 which matches the arguments. E.g.
func2({X, Y}) -> ... %% only accepts a tuple of size 2
func2([1, 2, 3])%% called with a list instead; will fail with function_clause
badarg with your function can be thrown because of wrong arguments to a built-in function: http://erlang.2086793.n4.nabble.com/function-badarg-td3645808.html
See a list of other failure reasons here: http://learnyousomeerlang.com/errors-and-exceptions
For debugging: 1) the latest Erlang release (R15B) should include line numbers in exception messages; 2) you can use the debugger which comes with Erlang.

Related

Erlang simple "spawn" gets undefined error in windows

I'm learning Erlang and I've written a simple module to test "spawn" function:
-module(concurrent).
-export([go/0, loop/0]).
go() ->
Pid2 = spawn(echo, loop, []).
loop() -> 2.
but when I run concurrent:go(). I get this error message:
=ERROR REPORT==== 10-Feb-2023::14:41:34.586000 === Error in process
<0.84.0> with exit value: {undef,[{echo,loop,[],[]}]}
I don't understand what I'm doing wrong.
You try to spawn a process running function loop from module echo. But you export function loop from module named concurrent and not echo.

How do I find the logs of Firefox?

While browsing the Firefox source code, I see that a lot of logs are present. I'd like to find them on runtime to help me understand and debug something.
For example, when taking a look at nsHttpConnection.cpp, Here's what I can find :
...
LOG(("restarting transaction #%p\n", this));
mTunnelProvider = nullptr;
...
Where did the LOG lines go ? How do I find the log file containing all the logs generated by Firefox ?
In the case of the file nsHttpConnection.cpp, the LOG() functions are macros defined in HttpLog.h.
here's an excerpt :
#define LOG1(args) \
MOZ_LOG(mozilla::net::gHttpLog, mozilla::LogLevel::Error, args)
You can see them as shortcuts for the more complete MOZ_LOG functions.
LOG1() -> Error
LOG2() -> Warning
LOG3() -> Info
LOG() = LOG4() -> Debug
LOG5() -> Verbose
If you want to get the logs for the nsHttp module, you can set 2 environment variables, and then run firefox :
set MOZ_LOG=nsHttp:5
set MOZ_LOG_FILE=http.log
firefox
or run firefox with the command line parameters :
firefox -MOZ_LOG=nsHttp:5 -MOZ_LOG_FILE=nsHttp.log
This enables Verbose level information (and higher) and places all output in the file nsHttp.log.
The MOZ_LOG variable is composed of as <module>:level.
You can also use a more general module all to include them all.
i.e. to log all Error level informations in the file all.log:
firefox -MOZ_LOG=all:1 -MOZ_LOG_FILE=all.log
For more information on how the MOZ_LOG variable is configured, you can take a look at prlog.h

Should pcall catch PANIC errors (ESP32 NodeMCU)?

I've such code:
print("AAAAAA")
local status, jobj = pcall(json.decode(docTxt))
print("BBBBBB")
decode method causes PANIC error, an it results in following console output:
AAAAAAA
PANIC: unprotected error in call to Lua API (json.lua:166: 'for' initial value must be a number)
Whole program beaks, BBBBB does not get printed to console.
Is this normal? Is pcall broken ?
I was able to figure it out: it can be configured in watchdog options for firmware compiler. Now I've have such setup, that it reboots on panic.

Julia doesn't like it when I add and remove processes without doing any parallel processing

UPDATE: Confirmed as a bug. For more detail, see the link and details provided by #ViralBShah below.
Julia throws a strange error when I add and remove processes (addprocs and rmprocs), but only if I don't do any parallel processing in between. Consider the following example code:
#Set parameters
numCore = 4;
#Add workers
print("Adding workers... ");
addprocs(numCore - 1);
println(string(string(numCore-1), " workers added."));
#Detect number of cores
println(string("Number of processes detected = ", string(nprocs())));
# Do some stuff (COMMENTED OUT)
# XLst = {rand(10, 1) for i in 1:8};
# XMean = pmap(mean, XLst);
#Remove the additional workers
print("Removing workers... ");
rmprocs(workers());
println("Done.");
println("Subroutine complete.");
Note that I've commented out the only code that actually does any parallel processing (the call to pmap). If I run this code on my machine (Julia 0.2.1, Ubuntu 14.04), I get the following output in the console:
Adding workers... 3 workers added.
Number of processes detected = 4
Removing workers... Done.
Subroutine complete.
fatal error on
In [86]: fatal error on 88: ERROR: 87: ERROR: connect: connection refused (ECONNREFUSED)
in yield at multi.jl:1540
connect: connection refused (ECONNREFUSED) in wait at task.jl:117
in wait_connected at stream.jl:263
in connect at stream.jl:878
in Worker at multi.jl:108
in anonymous at task.jl:876
in yield at multi.jl:1540
in wait at task.jl:117
in wait_connected at stream.jl:263
in connect at stream.jl:878
in Worker at multi.jl:108
in anonymous at task.jl:876
The first four lines are printed by my program, and seem to indicate that it runs to completion. But then I get a fatal error. Any ideas?
The most interesting thing about this error is if I uncomment the code with the call to pmap (ie if I actually do some parallel processing), the fatal error goes away.
This issue is being tracked at https://github.com/JuliaLang/julia/issues/7646 and I reproduce the answer by Amit Murthy:
pid 1 does an addprocs(3)
addprocs returns after it has established connections with all 3 new workers.
However, at this time the the connections between workers may not have been setup, i.e. from pids 3 -> 2, 4 -> 2 and 4 -> 3.
Now pid 1 calls rmprocs(workers()) , i.e., pids 2, 3 and 4.
As pid 2 exits, the connection attempt in 4 to 2, results in an error.
Since we have redirected the output of pid 4, to the stdout of pid 1, we see the same error printed.
The system is still in a consistent state, though the printing of said error messages may suggest something amiss.

Make valgrind stop immediately after first error

my program processes large errors and during development in produces large amount of output on the console. It suffers from memory corruption and I try to use valgrind to locate the error.
Unfortunately, i can't find the error messages among the output lines, and they flushing by too fast to cancel execution when they pop up. They have to be there in order to locate the error ( which element does cause the error and so on ). Redirecting then within my program doesn't work, just like piping the output does only redirect the program output, not the valgrind output.
Can you give me a hint how to solve this.
In addition to redirecting both program and Valgrind output to a file (as already suggested), you can use --db-attach=yes flag, which will cause your program to stop in the debugger right at the error.
This has the advantage that in addition to looking at the log your program produced, you can also look at other program state (that you are not logging).
If you want it to stop in the console (not in a file), here is a way to do it :
Use the parameter : --gen-suppressions=yes
When you debug it will stops like this :
==949== Thread 2:
==949== Invalid read of size 4
==949== at 0x7B62DC0: wcslen (wcslen.S:24)
==949== by 0x7B62D7D: wcsdup (wcsdup.c:29)
==949== by 0x52D0476: de_strdup(wchar_t*) (de_string.cpp:1442)
==949== by 0x437629: void de_format<>(c_de_string&, wchar_t*) (de_string.h:368)
==949== by 0x45F4FB: int db_select_group<>(s_db*, s_pqexec_param*, wchar_t*, wchar_t*, wchar_t*, wchar_t*, int, wchar_t*) (in /corto/goinfre/code2/cortod.repo/bin/x64/Debug/cortod)
==949== by 0x45EA96: check_oldgeom(c_cartod*) (cartod_funcs.cpp:114)
==949== by 0x45EBF8: armserv_update_geom(c_cartod*) (cartod_funcs.cpp:149)
==949== by 0x455EF9: c_cortosrv_thread::on_timeout() (cartod.cpp:163)
==949== by 0x52FE500: c_de_thread::loop() (de_thread.cpp:35)
==949== by 0x52FEE97: thread_loop(void*) (de_thread_priv_linux.cpp:85)
==949== by 0x506E181: start_thread (pthread_create.c:312)
==949== by 0x7BBA47C: clone (clone.S:111)
==949== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==949==
==949==
==949== ---- Print suppression ? --- [Return/N/n/Y/y/C/c] ----
Then you can go to the next one continue all etc.
The normal purpose of this parameter is to remove the false positives, by printing suppression that you can add in a file and pass it to valgrind using the parameter : --suppressions=<filename>
Valgrind 3.14.0 has --exit-on-first-error option:
ERROR-RELATED OPTIONS top
These options are used by all tools that can report errors, e.g.
Memcheck, but not Cachegrind.
...
--exit-on-first-error=<yes|no> [default: no]
If this option is enabled, Valgrind exits on the first error. A
nonzero exit value must be defined using --error-exitcode option.
Useful if you are running regression tests or have some other
automated test machinery.
This option must be used together with --error-exitcode option, so possible Valgrind invocation can be:
valgrind --exit-on-first-error=yes --error-exitcode=1 ...
Valgrind outputs to stderr (fd 2) by default. You can capture stderr by redirecting file desctiptor 2:
# Output to log file.
valgrind [options] > valgrind.log 2>&1
# View output interactively.
valgrind [options] 2>&1 | less
Or you could use the --log-fd option to change where output is sent:
valgrind [options] --log-fd=1 > valgrind.log
valgrind [options] --log-fd=1 | less
You can ask valgrind to save its output into file:
valgrind --log-file=<filename>
where <filename> is the file name for output. Later you can view this file with less or text editor.

Resources