The main application file is crashing becausing The server is affected by a format string bug when handles the players nicknames due the access to
an invalid memory zone.
The instruction executed is "cmp [EAX], 00000000" where EAX contains 4
of the bytes in the nickname and Crashes the Server.
I debugged and found that "%s" is missing before the logging string passed to the File_printf function. So i have tried to add this string via IDA Debugger and Successed. After entering these bytes now the server is crashing with the message "server is not vulnerable" before it was crashing with the message "server is vulnerable"
CODE
Bytes I have entered to patch the application:
RVA
00400000
OFFSET
0041dfad cc 68 ; push 0061d0dc
+ cc |0061d0dc
+ cc e8 ; call 0040d270
+ cc ^0040d270
+ cc 83 ; add esp,04
+ cc c4
+ cc 04
+ cc e9 ; jmp 0041e059
+ cc ^0041e059
0041e054 e8 e9 ; jmp 0041dfad
+ ?? ^0041dfad
0055DD63 cmp dword ptr [eax], 0
/*source*/
if ( *(_DWORD *)a1 )
a1 = sub_445D50();
if ( v2 )
{
--*(_DWORD *)(v2 + 4);
*(_DWORD *)a1 = *(_DWORD *)(v2 + 20);
*(_DWORD *)(v2 + 20) = a1;
}
else
{
v3 = *(_DWORD *)((a1 - 4) & 0xFFFFFFFC);
--dword_798ABD0;
sub_445D50();
memset(*(void **)(v3 + 8), 0xCDu, *(_DWORD *)(v3 + 16));
free((void *)v3);
}
}
/Hex Value/
0055DD63 83 38 00
After Testing the Server to Crash then the server Crashed with the message in the testing tool "Server is not Vulnerable" but Crashed.
And in the Debugger IDA i get this result with the detailed Message:
55dd63: The Instruction at 0x55DD63 referenced memory at 0x61616161, The memory could not be read -> 61616161 (exc.code c0000005, tid 4692)
Image 1
Image 2
Image 3
Image 4
Image 5
I can Share the testing tool also but not here because the testing tool has .simplese trojan and it may harm your pc, but i can share the Source code of the testing tool on Request.
The bug is caused by the logging function NetManager_LogMessage which
takes the text to dump, adds a timestamp (using snprintf) and then
passes the whole string to the function File_printf without the needed
format argument (%s) and you need to using the value 05 instead of 04 to make an ampty space to fool the bug. This trick work on many games and good luck
Related
I have a broadly used function foo(int a, int b) and I want to provide a special version of foo that performs differently if a is say 1.
a) I don't want to go through the whole code base and change all occurrences of foo(1, b) to foo1(b) because the rules on arguments may change and I dont want to keep going through the code base whenever the rules on arguments change.
b) I don't want to burden function foo with an "if (a == 1)" test because of performance issues.
It seems to me to be a fundamental skill of the compiler to call the right code based on what it can see in front of it. Or is this a possible missing feature of C++ that requires macros or something to handle currently.
Simply write
inline int foo(int a, int b)
{
if (a==1) {
// skip complex code and call easy code
call_easy(b);
} else {
// complex code here
do_complex(a, b);
}
}
When you call
foo(1, 10);
the optimizer will/should simply insert a call_easy(b).
Any decent optimizer will inline the function and detect if the function has been called with a==1. Also I think that the entire constexpr mentioned in other posts is nice, but not really necessary in your case. constexpr is very useful, if you want to resolve values at compile time. But you simply asked to switch code paths based on a value at runtime. The optimizer should be able to detect that.
In order to detect that, the optimizer needs to see your function definition at all places where your function is called. Hence the inline requirement - although compilers such as Visual Studio have a "generate code at link time" feature, that reduces this requirement somewhat.
Finally you might want to look at C++ attributes [[likely]] (I think). I haven't worked with them yet, but they are supposed to tell the compiler which execution path is likely and give a hint to the optimizer.
And why don't you experiment a little and look at the generated code in the debugger/disassemble. That will give you a feel for the optimizer. Don't forget that the optimizer is likely only active in Release Builds :)
Templates work in compile time and you want to decide in runtime which is never possible. If and only if you really can call your function with constexpr values, than you can change to a template, but the call becomes foo<1,2>() instead of foo(1,2); "performance issues"... that's really funny! If that single compare assembler instruction is the performance problem... yes, than you have done everything super perfect :-)
BTW: If you already call with constexpr values and the function is visible in the compilation unit, you can be sure the compiler already knows to optimize it away...
But there is another way to handle such things if you really have constexpr values sometimes and your algorithm inside the function can be constexpr evaluated. In that case, you can decide inside the function if your function was called in a constexpr context. If that is the case, you can do a full compile time algorithm which also can contain your if ( a== 1) which will be fully evaluated in compile time. If the function is not called in constexpr context, the function is running as before without any additional overhead.
To do such decision in compile time we need the actual C++ standard ( C++20 )!
constexpr int foo( int a, int)
{
if (std::is_constant_evaluated() )
{ // this part is fully evaluated in compile time!
if ( a == 1 )
{
return 1;
}
else
{
return 2;
}
}
else
{ // and the rest runs as before in runtime
if ( a == 0 )
{
return 3;
}
else
{
return 4;
}
}
}
int main()
{
constexpr int res1 = foo( 1,0 ); // fully evaluated during compile time
constexpr int res2 = foo( 2,0 ); // also full compile time
std::cout << res1 << std::endl;
std::cout << res2 << std::endl;
std::cout << foo( 5, 0) << std::endl; // here we go in runtime
std::cout << foo( 0, 0) << std::endl; // here we go in runtime
}
That code will return:
1
2
4
3
So we do not need to go with classic templates, no need to change the rest of the code but have full compile time optimization if possible.
#Sebastian's suggestion works at least in the simple case with all optimisation levels except -O0 in g++ 9.3.0 on Ubuntu 20.04 in c++20 mode. Thanks again.
See below disassembly always calling directly the correct subfunction func1 or func2 instead of the top function func(). A similar disassembly after -O0 shows only the top level func() being called leaving the decision to run-time which is not desired.
I hope this will work in production code and perhaps with multiple hard coded arguments.
Breakpoint 1, main () at p1.cpp:24
24 int main() {
(gdb) disass /m
Dump of assembler code for function main():
6 inline void func(int a, int b) {
7
8 if (a == 1)
9 func1(b);
10 else
11 func2(a,b);
12 }
13
14 void func1(int b) {
15 std::cout << "func1 " << " " << " " << b << std::endl;
16 }
17
18 void func2(int a, int b) {
19 std::cout << "func2 " << a << " " << b << std::endl;
20 }
21
22 };
23
24 int main() {
=> 0x0000555555555286 <+0>: endbr64
0x000055555555528a <+4>: push %rbp
0x000055555555528b <+5>: push %rbx
0x000055555555528c <+6>: sub $0x18,%rsp
0x0000555555555290 <+10>: mov $0x28,%ebp
0x0000555555555295 <+15>: mov %fs:0x0(%rbp),%rax
0x000055555555529a <+20>: mov %rax,0x8(%rsp)
0x000055555555529f <+25>: xor %eax,%eax
25
26 X x1;
27
28 int b=1;
29 x1.func(1,b);
0x00005555555552a1 <+27>: lea 0x7(%rsp),%rbx
0x00005555555552a6 <+32>: mov $0x1,%esi
0x00005555555552ab <+37>: mov %rbx,%rdi
0x00005555555552ae <+40>: callq 0x55555555531e <X::func1(int)>
30
31 b=2;
32 x1.func(2,b);
0x00005555555552b3 <+45>: mov $0x2,%edx
0x00005555555552b8 <+50>: mov $0x2,%esi
0x00005555555552bd <+55>: mov %rbx,%rdi
0x00005555555552c0 <+58>: callq 0x5555555553de <X::func2(int, int)>
33
34 b=3;
35 x1.func(1,b);
0x00005555555552c5 <+63>: mov $0x3,%esi
0x00005555555552ca <+68>: mov %rbx,%rdi
0x00005555555552cd <+71>: callq 0x55555555531e <X::func1(int)>
36
37 b=4;
38 x1.func(2,b);
0x00005555555552d2 <+76>: mov $0x4,%edx
0x00005555555552d7 <+81>: mov $0x2,%esi
0x00005555555552dc <+86>: mov %rbx,%rdi
0x00005555555552df <+89>: callq 0x5555555553de <X::func2(int, int)>
39
40 return 0;
0x00005555555552e4 <+94>: mov 0x8(%rsp),%rax
0x00005555555552e9 <+99>: xor %fs:0x0(%rbp),%rax
0x00005555555552ee <+104>: jne 0x5555555552fc <main()+118>
0x00005555555552f0 <+106>: mov $0x0,%eax
0x00005555555552f5 <+111>: add $0x18,%rsp
0x00005555555552f9 <+115>: pop %rbx
0x00005555555552fa <+116>: pop %rbp
0x00005555555552fb <+117>: retq
0x00005555555552fc <+118>: callq 0x555555555100 <__stack_chk_fail#plt>
End of assembler dump.
I am trying to recurse directories in a c++ program I am creating using the QT creator application. For some reason, neither QDir::entryList nor QDirIterator seem to work. Using QDirIterator I can get the second directory down but it goes no further. A similar thing happens when I use QDir::entryList with nested foreach loops. Ultimately, I'd like to get the last directory, which contains no other directories, in a chain of directories.
This is intended to be cross-platform so it cannot be OS specific. I'd also like to avoid lots of switches for different OS' as I'd like to not have to work on it later and simply use it (potentially forever). I have tried foreach loops, while loops, anything I could think of.
QDir Code:
QStringList GetLastSubDirs(QDir baseDirectory) {
QStringList result;
baseDirectory.setFilter( QDir::Dirs|QDir::NoDotAndDotDot );
QStringList nonEmptyDirs(baseDirectory.path());
while (nonEmptyDirs.size() > 0) {
foreach (QString d, nonEmptyDirs) {
QDir sd(d);
foreach (QDir checkingDir, sd.entryList(QDir::Dirs|QDir::NoDotAndDotDot)) {
if (checkingDir.entryList().size() == 0) {
result.append(checkingDir.path());
} else {
nonEmptyDirs.append(checkingDir.path());
}
}
nonEmptyDirs.removeOne(d);
}
}
if (result.size() == 0) {
result = QStringList(baseDirectory.path());
}
return result;
}
};
Here is the QDirIterator code:
class Directories
{
public:
QStringList GetLastSubDirs(QDir baseDirectory) {
QStringList result;
baseDirectory.setFilter( QDir::Dirs|QDir::NoDotAndDotDot );
QDirIterator it(QDir::currentPath() + "/" + baseDirectory.path(), QDirIterator::Subdirectories);
while(it.hasNext()) {
QDir curWorkDir(it.path());
curWorkDir.setFilter( QDir::Dirs|QDir::NoDot|QDir::NoDotDot );
if(curWorkDir.entryList().size() >= 1) {
foreach (QDir d, curWorkDir.entryList()) {
d.setFilter( QDir::Dirs|QDir::NoDot|QDir::NoDotDot );
if (d.entryList().size() <= 0) {
result.append(d.path());
}
}
} else {
result.append(curWorkDir.path());
}
it.next();
}
if (result.size() == 0) {
result = QStringList(baseDirectory.path());
}
return result;
}
};
Debugger Output
1 Directories::GetLastSubDirs main.cpp 56 0x555555559ba9
2 Games::Games main.cpp 80 0x555555559f98
3 __static_initialization_and_destruction_0 main.cpp 104 0x55555555931b
4 _GLOBAL__sub_I_main.cpp(void) main.cpp 120 0x55555555934e
5 __libc_csu_init 0x55555555cd9d
6 __libc_start_main libc-start.c 247 0x7ffff54ed270
7 _start 0x555555558f2a
Disassembler output:
0x555555558f00 31 ed xor %ebp,%ebp
0x555555558f02 <+ 2> 49 89 d1 mov %rdx,%r9
0x555555558f05 <+ 5> 5e pop %rsi
0x555555558f06 <+ 6> 48 89 e2 mov %rsp,%rdx
0x555555558f09 <+ 9> 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
0x555555558f0d <+ 13> 50 push %rax
0x555555558f0e <+ 14> 54 push %rsp
0x555555558f0f <+ 15> 4c 8d 05 aa 3e 00 00 lea 0x3eaa(%rip),%r8 # 0x55555555cdc0 <__libc_csu_fini>
0x555555558f16 <+ 22> 48 8d 0d 33 3e 00 00 lea 0x3e33(%rip),%rcx # 0x55555555cd50 <__libc_csu_init>
0x555555558f1d <+ 29> 48 8d 3d 74 01 00 00 lea 0x174(%rip),%rdi # 0x555555559098 <main(int, char**)>
0x555555558f24 <+ 36> ff 15 c6 70 20 00 callq *0x2070c6(%rip) # 0x55555575fff0
0x555555558f2a <+ 42> f4 hlt
I expect this particular snippet of code to recurse directories until it has cleared any directory that contains other directories. Instead it will only go down one level and stop. For some reason when querying the entryList().size() of these directories it always comes back with 0, even if the directory contains other directories, unless I include . and .. and then it just loops forever because it wasn't intended to handle that.
I don't know why you make it so complicated. The documentation says this:
The QDirIterator class provides an iterator for directory entrylists.
You can use QDirIterator to navigate entries of a directory one at a time. It is similar to QDir::entryList() and QDir::entryInfoList(), but because it lists entries one at a time instead of all at once, it scales better and is more suitable for large directories. It also supports listing directory contents recursively, and following symbolic links. Unlike QDir::entryList(), QDirIterator does not support sorting.
The QDirIterator constructor takes a QDir or a directory as argument. After construction, the iterator is located before the first directory entry. Here's how to iterate over all the entries sequentially:
QDirIterator it("/etc", QDirIterator::Subdirectories);
while (it.hasNext()) {
qDebug() << it.next();
// /etc/.
// /etc/..
// /etc/X11
// /etc/X11/fs
// ...
}
QDirIterator is already recursive when supplying QDirIterator::Subdirectories.
QDir::EntryList returns the names of the child entries, not their full paths. You need to append the name to the parent path to get the full path.
Given a hierarchy:
basedir/
child1/
child2/
grandchild1/
grandchild2/
calling entryList on baseDir will return ["child1", "child2"], not ["basedir/child1", "basedir/child2"]
As I said in the comments: I do not expect this code to work even when you fix that problem. You are modifying nonEmptyDirs inside a foreach loop over nonEmptyDirs. That feels dangerous. It certainly wouldn't work inside a C++11 ranged-for loop. I suggest writing the foreach macro out by hand to check that it will work. In particularly, removing the entry in a list which the current iterator points to, is not going to end well.
From the Qt documentation ... last sentence most important
Qt automatically takes a copy of the container when it enters a foreach loop. If you modify the container as you are iterating, that won't affect the loop. (If you do not modify the container, the copy still takes place, but thanks to implicit sharing copying a container is very fast.)
Since foreach creates a copy of the container, using a non-const reference for the variable does not allow you to modify the original container. It only affects the copy, which is probably not what you want.
I am currently working with an application trying to integrate BreakPad into a Qt application. I found a page that helped me out a bunch with the initial setup and quirks.
https://github.com/JPNaude/dev_notes/wiki/Using-Google-Breakpad-with-Qt
I still cannot get it to work for actual exceptions. I created a demo application and it is having the same issue. Here are the steps I am following to test. I am testing in debug right now.
Build the application Run dump_syms.exe BreakpadTest.pdb > BreakpadTest.sym
Run the application and generate a dump file
Run minidump_stackwalk dumpfile.dmp symbols > out.txt 2>&1
Check out.txt for the file path to place the BreakpadTest.sym
Move the BreakpadTest.sym file to the proper location
Run minidump_stackwalk dumpfile.dmp symbols > out.txt 2>&1 again
This leaves me with an out.txt file.
When I call dumpFunc in my demo application which executes this code
Breakpad::CrashHandler::instance()->writeMinidump();
I get the folowing output
Thread 0 (crashed)
0 BreakpadTest.exe!Breakpad::CrashHandler::writeMinidump() [crashhandler.cpp : 118 + 0xb]
eip = 0x00c03a44 esp = 0x00affe18 ebp = 0x00affe48 ebx = 0x009fe000
esi = 0x00c01960 edi = 0x00c01960 eax = 0x00affaf0 ecx = 0x00affaf0
edx = 0x00affdbc efl = 0x00000216
Found by: given as instruction pointer in context
1 BreakpadTest.exe!dumpFunc() [main.cpp : 13 + 0xb]
eip = 0x00c0364f esp = 0x00affe50 ebp = 0x00affe50
Found by: call frame info
2 BreakpadTest.exe!main [main.cpp : 25 + 0x4]
eip = 0x00c03746 esp = 0x00affe58 ebp = 0x00affea0
Found by: call frame info
3 BreakpadTest.exe!WinMain [qtmain_win.cpp : 113 + 0xc]
eip = 0x00c14d3d esp = 0x00affea8 ebp = 0x00affed4
Found by: call frame info
4 BreakpadTest.exe!invoke_main [exe_common.inl : 94 + 0x1a]
eip = 0x00c13b7e esp = 0x00affedc ebp = 0x00affeec
Found by: call frame info
5 BreakpadTest.exe!__scrt_common_main_seh [exe_common.inl : 253 + 0x4]
eip = 0x00c13a00 esp = 0x00affef4 ebp = 0x00afff44
Found by: call frame info
6 BreakpadTest.exe!__scrt_common_main [exe_common.inl : 295 + 0x4]
eip = 0x00c1389d esp = 0x00afff4c ebp = 0x00afff4c
Found by: call frame info
7 BreakpadTest.exe!WinMainCRTStartup [exe_winmain.cpp : 16 + 0x4]
eip = 0x00c13b98 esp = 0x00afff54 ebp = 0x00afff54
Found by: call frame info
8 kernel32.dll + 0x162c3
eip = 0x76c962c4 esp = 0x00afff5c ebp = 0x00afff68
Found by: call frame info
9 ntdll.dll + 0x60fd8
eip = 0x77850fd9 esp = 0x00afff70 ebp = 0x00afffb0
Found by: previous frame's frame pointer
10 ntdll.dll + 0x60fa3
eip = 0x77850fa4 esp = 0x00afffb8 ebp = 0x00afffc0
Found by: previous frame's frame pointer
This is good and what I want. But when I actually cause an exception with badFunc().
int *myNull = NULL;
*myNull = 42;
I get the following output
Thread 0 (crashed)
0 ntdll.dll + 0x6e5fc
eip = 0x7785e5fc esp = 0x00eff09c ebp = 0x00eff10c ebx = 0x00000001
esi = 0x00000000 edi = 0x00000368 eax = 0x00000000 ecx = 0x6d278097
edx = 0x00000000 efl = 0x00000206
Found by: given as instruction pointer in context
1 KERNELBASE.dll + 0xcad51
eip = 0x74d7ad52 esp = 0x00eff114 ebp = 0x00eff120
Found by: previous frame's frame pointer
2 BreakpadTest.exe!google_breakpad::ExceptionHandler::WriteMinidumpOnHandlerThread(_EXCEPTION_POINTERS *,MDRawAssertionInfo *) [exception_handler.cc : 720 + 0x11]
eip = 0x009f72d0 esp = 0x00eff128 ebp = 0x00eff138
Found by: previous frame's frame pointer
3 BreakpadTest.exe!google_breakpad::ExceptionHandler::HandleException(_EXCEPTION_POINTERS *) [exception_handler.cc : 504 + 0xd]
eip = 0x009f6d71 esp = 0x00eff140 ebp = 0x00eff178
Found by: call frame info
4 KERNELBASE.dll + 0x15d411
eip = 0x74e0d412 esp = 0x00eff180 ebp = 0x00eff20c
Found by: call frame info
5 ntdll.dll + 0x9e0bc
eip = 0x7788e0bd esp = 0x00eff214 ebp = 0x00effa10
Found by: previous frame's frame pointer
6 ntdll.dll + 0x60fa3
eip = 0x77850fa4 esp = 0x00effa18 ebp = 0x00effa20
Found by: previous frame's frame pointer
This is not the actual stack trace where the exception occurred. Any ideas on what is going wrong or how I can change it to get the actual stack?
Demo Application
http://s000.tinyupload.com/?file_id=26352983283926785193
I have been recently down the same rabbit hole as well. Taking resources from many places, I put together everything I found in this repo.
One of the things that might affect the stack output is if the optimization level that you are using to compile your application. It doesn't matter if you force the creation of debug symbols. The stack will sometimes appear incorrect if you apply any optimization, so what you can try is to disable optimization in your Qt project (*.pro file) for your release builds as follows:
CONFIG *= force_debug_info
QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO -= -O2
My problem is the following. I have a code unit composed of various c files, say for example
file1.c
file2.c
file3.c
that are all compiled with GCC to a unique object "object.o", which in turn is then linked with other objects to give at the end the executable "application.out", running on VxWorks.
Since I'm doing unit testing on "object.o", my need is to stimulate all the possible ways through the code. Specifically, there are situations where I should have mock functions executed instead of original ones in order to simulate error occurrences.
Suppose for example that there is a function "func_caller" that I'm trying to test that, at some point in the execution, makes a call to another function "func_called" (declared as static).
Since I DON'T WANT TO MODIFY THE ORIGINAL CODE, I wonder if there is a way to manipulate the instruction pointers in such a way that when "func_called" is called, it actually executes another mock function "func_called_mock" and the caller "func_caller" does not notice anything.
Thanks in advance.
The most direct method of overriding function calls would be to use VxWorks's load time linking. Consider the following source:
file1.c:
#include <stdio.h>
int function1 (void);
int function1 ()
{
printf ("function1 called\n");
return 1;
}
file2.c:
#include <stdio.h>
int function2 (void);
int function2 ()
{
printf ("function2 called\n");
return 2;
}
file3.c:
int function1 (void);
int function2 (void);
int function3 (void);
int function3 ()
{
function1 ();
function2 ();
return 0;
}
mock.c:
#include <stdio.h>
int function1 (void);
int function2 (void);
int function1 ()
{
printf ("mock function1 called\n");
return 1;
}
int function2 ()
{
printf ("mock function2 called\n");
return 2;
}
When you load an object, its functions are added to the global symbol table.
-> ld < file1.o
value = 273740816 = 0x1050f410
-> lkup "function"
function1 0x108b0000 text (file1.o)
value = 0 = 0x0
->
When you load an object that uses functions already in the symbol table, each call will be immediately resolved to the last address associated with that symbol in the table.
-> ld < file2.o
value = 292535232 = 0x116fbbc0
-> ld < file3.o
value = 292537592 = 0x116fc4f8
-> lkup "function"
function1 0x108b0000 text (file1.o)
function2 0x108d0000 text (file2.o)
function3 0x108f0000 text (file3.o)
value = 0 = 0x0
-> l function3
function3:
0x108f0000 55 PUSH EBP
0x108f0001 89 e5 MOV EBP, ESP
0x108f0003 56 PUSH ESI
0x108f0004 57 PUSH EDI
0x108f0005 e8 f6 ff fb ff CALL function1
0x108f000a e8 f1 ff fd ff CALL function2
0x108f000f 31 c0 XOR EAX, EAX
0x108f0011 5f POP EDI
0x108f0012 5e POP ESI
0x108f0013 89 ec MOV ESP, EBP
value = 0 = 0x0
-> function3
function1 called
function2 called
value = 0 = 0x0
->
Although l() helpfully displays function names, no symbols are actually loaded into memory with the object. Instead, a call to the last address associated with the function is loaded. So, a previously loaded function may be overridden by loading another function of the same name.
-> unld "file3.o"
value = 0 = 0x0
-> ld < mock.o
value = 292537592 = 0x116fc4f8
-> ld < file3.o
value = 292539496 = 0x116fcc68
-> lkup "function"
function1 0x108f0000 text (mock.o)
function1 0x108b0000 text (file1.o)
function2 0x108f0020 text (mock.o)
function2 0x108d0000 text (file2.o)
function3 0x10910000 text (file3.o)
value = 0 = 0x0
-> l function3
function3:
0x10910000 55 PUSH EBP
0x10910001 89 e5 MOV EBP, ESP
0x10910003 56 PUSH ESI
0x10910004 57 PUSH EDI
0x10910005 e8 f6 ff fd ff CALL function1
0x1091000a e8 11 00 fe ff CALL function2
0x1091000f 31 c0 XOR EAX, EAX
0x10910011 5f POP EDI
0x10910012 5e POP ESI
0x10910013 89 ec MOV ESP, EBP
value = 0 = 0x0
-> function3
mock function1 called
mock function2 called
value = 0 = 0x0
->
Note that for this method to work, the called and calling functions cannot be compiled into the same object. You might also note that the addresses to be called don't match those in the symbol table. This is the result of executing the above in VxSim. The VxSim loader actually calls the loader of the underlying operating system. So, these addresses don't match those in the symbol table and the assembly reflects the underlying Pentium architecture on which WorkBench is being run.
A function call may also be overridden by directly manipulating the address to be called in memory. This method is going to be implementation dependent. Below, this is demonstrated for source compiled for PPC using the gcc -mlongcall option. This has been run on an actual target, not VxSim.
-> ld < file1.o
value = 33538216 = 0x1ffc0a8 = function1 + 0x498
-> ld < file2.o
value = 33548336 = 0x1ffe830 = function2 + 0x80
-> ld < mock.o
value = 33549600 = 0x1ffed20 = function2 + 0x570
-> ld < file3.o
value = 33550744 = 0x1fff198 = function2 + 0x9e8
->
-> lkup "function"
function1 0x01ffbef8 text (mock.o)
function1 0x01ffbc10 text (file1.o)
function2 0x01ffbf58 text (mock.o)
function2 0x01ffe7b0 text (file2.o)
function3 0x01ffe558 text (file3.o)
value = 0 = 0x0
->
-> function3
mock function1 called
mock function2 called
value = 0 = 0x0
->
-> l function3
function3:
0x1ffe558 9421ffe8 stwu r1,-24(r1)
0x1ffe55c 7c0802a6 mfspr r0,LR
0x1ffe560 93a1000c stw r29,12(r1)
0x1ffe564 93c10010 stw r30,16(r1)
0x1ffe568 93e10014 stw r31,20(r1)
0x1ffe56c 9001001c stw r0,28(r1)
0x1ffe570 7c3f0b78 or r31,r1,r1
0x1ffe574 3d200200 lis r9,512
0x1ffe578 3ba9bef8 addi r29,r9,-16648
0x1ffe57c 7fa803a6 mtspr LR,r29
value = 33547648 = 0x1ffe580 = function3 + 0x28
->
-> *0x1ffe578
function3 + 0x20 = 0x1ffe578: value = 1000980216 = 0x3ba9bef8
-> *0x1ffe578 = 0x3ba9bc10
function3 + 0x20 = 0x1ffe578: value = 1000979472 = 0x3ba9bc10
-> *0x1ffe578
function3 + 0x20 = 0x1ffe578: value = 1000979472 = 0x3ba9bc10
->
-> function3
function1 called
mock function2 called
value = 0 = 0x0
->
Obviously, directly manipulating pointers in memory is going to quickly become tedious. Additionally, memory protection will prevent you from changing RTPs or objects loaded in VxSim. (Hence, why I ran this on actual hardware.) I mention the possibility, primarily because it seems to best match your question's statement.
Finally, for non-trivial unit testing, you may want to consider a tool designed specifically for the task. Try a search on "vxworks unit test framework". I don't have deep experience with any particular tool (and don't want to come across spammy). Perhaps, someone else here can provide a good suggestion.
I'm debugging this code :
len = NGX_SYS_NERR * sizeof(ngx_str_t);
ngx_sys_errlist = malloc(len);
if (ngx_sys_errlist == NULL) {
goto failed;
}
for (err = 0; err < NGX_SYS_NERR; err++) {
But in gdb if (ngx_sys_errlist == NULL) { is skipped directly:
(gdb)
59 ngx_sys_errlist = malloc(len);
(gdb) n
64 for (err = 0; err < NGX_SYS_NERR; err++) {
I also have experienced this before,but never knows the reason,anyone knows?
Is it a bug?
UPDATE
0x000000000041be9d <ngx_strerror_init+0>: mov %rbx,-0x30(%rsp)
0x000000000041bea2 <ngx_strerror_init+5>: mov %rbp,-0x28(%rsp)
0x000000000041bea7 <ngx_strerror_init+10>: mov %r12,-0x20(%rsp)
0x000000000041beac <ngx_strerror_init+15>: mov %r13,-0x18(%rsp)
0x000000000041beb1 <ngx_strerror_init+20>: mov %r14,-0x10(%rsp)
0x000000000041beb6 <ngx_strerror_init+25>: mov %r15,-0x8(%rsp)
0x000000000041bebb <ngx_strerror_init+30>: sub $0x38,%rsp
0x000000000041bebf <ngx_strerror_init+34>: mov $0x840,%edi
0x000000000041bec4 <ngx_strerror_init+39>: callq 0x402388 <malloc#plt>
0x000000000041bec9 <ngx_strerror_init+44>: mov %rax,0x26e718(%rip) # 0x68a5e8 <ngx_sys_errlist>
0x000000000041bed0 <ngx_strerror_init+51>: mov $0x840,%r12d
0x000000000041bed6 <ngx_strerror_init+57>: test %rax,%rax
0x000000000041bed9 <ngx_strerror_init+60>: je 0x41bf56 <ngx_strerror_init+185>
0x000000000041bedb <ngx_strerror_init+62>: mov $0x0,%r13d
0x000000000041bee1 <ngx_strerror_init+68>: mov $0x0,%r14d
0x000000000041bee7 <ngx_strerror_init+74>: mov $0x0,%r15d
0x000000000041beed <ngx_strerror_init+80>: mov %r13d,%edi
0x000000000041bef0 <ngx_strerror_init+83>: callq 0x402578 <strerror#plt>
UPDATE
Nobody else ever met the same thing in using gdb? It happens to me frequently when debugging.
Most likely the two statements were optimized into a single set-and-test expression, which then can't be decomposed into the original two lines. The generated pseudocode is likely to be something like
call _malloc
jz _failed
mov acc, _ngx_sys_errlist
where the test now happens before the assignment; do you let the source level trace go backwards to reflect this?
please check,
a) if you are debugging release build (if there exists one)
b) if your source file is modified
if you still have the issue, please provide the details (Complier with version, degugger version , platform and code ...)