You are on Linux?
The debugger is slightly smarter in working out stack frames.
You application contains debug info (usually DWARF).
Both the debugger, and the "build in stack log" use this debug info, to get the filenames and lines.
"ExecuteThreadQueueEntry" is from the unit "classes" and it has no debug info (for that you need a custom build rtl / rebuild fpc). So the log can not translate this.
The debugger searches additional info (in this case symbols that are used by the linker) to get the name. As you can see, those symbols only give a mangled name (with _$$_ and stuff).
Then the line 7FE7C1.... this is outside your app. This address is from some library (maybe qt, maybe kernel). So there is no debug info.
Of course this line does also have a caller, yet neither the log nor the debugger show it (gdb may sometimes do, gdb is yet a bit smarter with that).
The reason is that there is no 100% way to find the caller. Most code follows certain rules. And if code follows those rules, then the debugger (and often log too) can find the caller. Otherwise they can not.
The main question, the actual line of the crash, that is missing in the log.
It comes down to the log code (in this case the code that prepares the list of "frames") not being smart enough. There is no code at 0x0000000, so this "no code" does not follow the convention. The log code does not realize that a call to 0x0000000 was made.
So it assumes your current procedure is at 0x00000 which you get in the param "addr".
Only, it thinks that 0x0000000 was reached just by going forward, and that there was no call. So when it looks for what called your code, then it goes to the caller of your function, rather than to your function.
I don't know of any way to work around that.
I remember I had to add special code to the debugger to handle that very same situation. But the debugger has access to more data. Data that your code can't get access to (afaik)