Help!
I am receiving this error when viewing the contents of an inbound function parameters in my Delphi 4 application.
The code calls a function in a dll with 3 parameters (app.handle, pchar, boolean)
The declaring function is in externs.pas and declared as:
function AdjustVoucherDifference(hOwner :HWnd; Receipt_ID :PChar;
bCommit: Boolean): boolean; stdcall;
external 'FBCoupon.dll' name 'AdjustVoucherDifference';
in another source file, the code calls it as:
AdjustVoucherDifference(Application.Handle, PChar(Receipt_ID), true);
When stepping through the code in debug mode, I can see valid values in the source file, but when it breaks on the line in externs.pas, the tooltip for the values (or CTRL+F7) shows that the symbols have been eliminated from the linker and I receive exceptions when the execution is in the dll.
The DLL is developed in CBuilder4 and the particular function is declared as:
BOOL __stdcall __DLLTYPE__ AdjustVoucherDifference(HWND hOwner,
char *receipt_id, bool commit);
Compiler optimization is turned off.
Thanks!!!
Set a breakpoint before the call to the external function (not a breakpoint on the external declaration).
Open the debugger disassembly window. (I forget the exact menu path to get there)
Step through the machine instructions one at a time. You don't need to understand all of them (though it doesn't hurt), but keep a sharp eye out for jump and call instructions.
There will be a bit of chatter as the code sets up the parameters for the call, then a call instruction.
Follow (step into) the call instruction. Since this is an external call, expect to see a jump indirect instruction.
Follow that jump to its destination. You should now be inside the C++ DLL. If you built the DLL in CBuilder with debug info, you should have symbol info and source line info as well.
If your parameter declarations on the Delphi side don't match the expectations on the C++ side, then you should start to see things going awry on the C++ side of the call, which could lead to an access violation exception or a runtime error generated by the C++ dll.
The linker isn't affected by compiler optimizations. The linker will "smartlink out" any routine that it can prove is will never be called in your program. Unfortunately, this means it's not available for the debugger to call into.
My solution to this, when it's happened to me in the past, is generally to put a meaningless call to the routine in question in an initialization section. The smartlinker won't mess with those. Can you do this without causing any errors?
initialization
AdjustVoucherDifference(0, '', true); //DO NOT SMARTLINK THIS OUT!
end;
Note that BOOL and Boolean are different. BOOL is defined in Windows.pas as
type
BOOL = LongBool;
so SizeOf(BOOL) = 4 while SizeOf(Boolean) = 1
Even if it would not help you with your problem, replace Boolean by BOOL (or LongBool) in Delphi declaration to make the declaration correct.
Related
I'm working on an old program that doesn't save or load its files anymore. While looking around in a DLL for a place to start, I noticed that there is some logging functionality that is disabled by default but should still work. Using a proxy DLL, I managed to activate logging by calling the right functions from the real DLL. However, I got stuck at using the actual logging functions, as the program crashes with Error 0xc0000142 whenever I get close to using them. All binaries involved are 32 bit.
Here's what I'm doing in my proxy DLL:
// undname ?ForceDebugLog##YAXXZ = void __cdecl ForceDebugLog(void)
typedef void (*FDLAddr_t)(void);
FDLAddr_t ForceDebugLog;
// undname ?LogInfo##YAXPBDZZ = void __cdecl LogInfo(char const *,...)
typedef void (*LIAddr_t)(char const *, ...);
LIAddr_t LogInfo;
// called on DLL_PROCESS_ATTACH
void setupFuncs() {
HMODULE trueDll= GetModuleHandleA(".\\realDll.dll");
ForceDebugLog = (FDLAddr_t)GetProcAddress(realDll, "?ForceDebugLog##YAXXZ");
// LogInfo = (LIAddr_t)GetProcAddress(realDll, "?LogInfo##YAXPBDZZ");
}
Now, I can just do ForceDebugLog() and logging gets enabled. However, as soon as I uncomment the LogInfo line, the program crashes on startup with Windows showing the error 0xc0000142.
Further experimentation shows that GetProcAddress returns the address of LogInfo in the DLL, i.e. this is working correctly. Also, everything works if LogInfo was a FARPROC. As soon as I add the cast to LIAddr_t, the error comes back.
How can I work around this issue? Do I need to take a different approach for functions with varargs? If this is a problem that has to be solved using C++ constructs, that's fine too.
I apologise for the waste of everyone's time.
While looking at my DLL in ghidra, I noticed that there were some strings defined that appeared nowhere in my code. As it turns out, some old object files from earlier experiments were accidentally linked into the DLL. One of the experiments was a reimplementation of LogInfo which caused the compiler/linker to produce an incorrect result without throwing an error or warning (unless /wd5045 suppresses it, which I highly doubt).
This has the side effect that I now have to rework my makefile. Oh joy.
I've been stuck for a while on how to set up a callback when an exception occurs.
I have this test code:
void main()
{
long * bad = (long*)0x0A000000; //Invalid address
//When the following line gets executed
//it causes an error and the debugger sends me to an assembly file.
*bad = 123456789;
}
The assembly file that I am sent to looks like this(fragment of the real file):
.macro DEFAULT_ISR_HANDLER name=
.thumb_func
.weak \name
\name:
1: b 1b /* endless loop */
.endm
DEFAULT_ISR_HANDLER SRC_IRQHandler /*Debugger stops on this line*/
As I understand DEFAULT_ISR_HANDLER is a macro that defines an endless loop.
What I want to do is define my own function in a C file, that I could call when an exception occurs, instead of calling whats defined in the DEFAULT_ISR_HANDLER macro.
My question is, How would I define a macro, in that assembly, that calls an specific C function?
Hopefully I explained myself. Any information or direction around this topic is appreciated.
In case it's relevant I am using GCC ARM compiler v5.4_2016q3
Thanks,
Isaac
EDIT
I am using a Cortex-M3.
Until now I realized I was talking about processor exceptions. According to the datasheet there is a list with 16 exception types.
Apparently, the way it works is that all the exception types are being redirected to the macro, which in turn calls some thumb function and afterwards an endless loop(according to DEFAULT_ISR_HANDLER above in code).
What I would like to do is define my own function in a C file, for convenience, so every time any type of processor exception appear, I could control how to proceed.
You have two options:
Just define a C function with the void SRC_IRQHandler(void) signature and since the macro is defining the default handler as weak, your function will override the default handler in the linking stage.
There should be a place in your project where SRC_IRQHandler is placed in what is called a Vector Table in the Cortex-M3 architecture. You can replace the name of this function with your own C function and your function will be called when this interrupt (exception) happens.
The cortex-m family in general has well more than 16 exceptions there are those plus as many interrupts are implemented by that core, 32, 64, 128, 256. But it is all fundamentally the same. The way the cortex-m family works is they perform the EABI call for you if you will, they preserve some of the registers and then start execution at the address called out in the vector table done in such a way that you can have the address of a normally compiled C function directly in the table. Historically you needed to wrap that function with some code to preserve and restore the state and often instruction sets have a special return from interrupt, but the cortex-m they did a bit different.
so knowing that then the next question is how do you get that address in the table, and that depends on your code, build system, etc. Those handlers might be setup to point to an address in ram and maybe you are running on an RTOS and there is a function you call runtime to register a function for an exception then the RTOS changes the code or some data value in ram that is tied into their handler which essentially wraps around yours. or you are making the vector table in assembly or some other tool specific thing (although assembly is there, works and easy) and you simply count down the right number of entries (or add a hundred more entries so you can count down to the right entry) and place the name of your C function.
good idea to disassemble or do some other check on the result before running to double check that you have placed the handler address at the right physical address for that interrupt/exception.
I am building one of the projects and I am looking at the generated list file.(target: x86-64) My code looks like:
int func_1(var1,var2){
asm_inline_(
)
func_2(var1,var2);
return_1;
}
void func_2(var_1,var_2){
asm __inline__(
)
func_3();
}
/**** Jump to kernel ---> System call stub in assembly. This func in .S file***/
void func_3(){
}
When I see the assembly code, I find "jmp" instruction is used instead of "call-return" pair when calling func_2 and func_3. I am sure it is one of the compiler optimization and I have not explored how to disable it. (GCC)
The moment I add some volatile variables to func_2 and func_3 and increment them then "jmp" gets replaced by "call-ret" pair.
I am bemused to see the behavior because those variables are useless and they don't serve any purpose.
Can someone please explain the behavior?
Thanks
If code jumps to the start of another function rather than calling it, when the jumped-to function returns, it will return back to the point where the outer function was called from, ignoring any more of the first function after that point. Assuming the behaviour is correct (the first function contributed nothing else to the execution after that point anyway), this is an optimisation because it reduces the number of instructions and stack manipulations by one level.
In the given example, the behaviour is correct; there's no local stack to pop and no value to return, so there is no code that needs to run after the call. (return_1, assuming it's not a macro for something, is a pure expression and therefore does nothing no matter its value.) So there's no reason to keep the stack frame around for the future when it has nothing more to contribute to events.
If you add volatile variables to the function bodies, you aren't just adding variables whose flow the compiler can analyse - you're adding slots that you've explicitly told the compiler could be accessed outside the normal control flow it can predict. The volatile qualifier warns the compiler that even though there's no obvious way for the variables to escape, something outside has a way to get their address and write to it at any time. So it can't reduce their lifetime, because it's been told that code outside the function might still try to write to that stack space; and obviously that means the stack frame needs to continue to exist for its entire declared lifespan.
This code compiles, but no surprises, it fails while linking (no main found):
Listing 1:
void main();
Link error: \mingw\lib\libmingw32.a(main.o):main.c:(.text+0x106) undefined reference to _WinMain#16'
But, the code below compiles and links fine, with a warning:
Listing 2:
void (*main)();
warning: 'main' is usually a function
Questions:
In listing 1, linker should have
complained for missing "main". Why
is it looking for _WinMain#16?
The executable generated from
listing 2 simply crashes. What is
the reason?
Thanks for your time.
True, main doesn't need to be a function. This has been exploited in some obfuscated programs that contain binary program code in an array called main.
The return type of main() must be int (not void). If the linker is looking for WinMain, it thinks that you have a GUI application.
In most C compilation systems, there is no type information associated with symbols that are linked. You could declare main as e.g.:
char main[10];
and the linker would be perfectly happy. As you noted, the program would probably crash, uless you cleverly initialized the contents of the array.
Your first example doesn't define main, it just declares it, hence the linker error.
The second example defines main, but incorrectly.
Case 1. is Windows-specific - the compiler probably generates _WinMain symbol when main is properly defined.
Case 2. - you have a pointer, but as static variable it's initialized to zero, thus the crash.
On Windows platforms the program's main unit is WinMain if you don't set the program up as a console app. The "#16" means it is expecting 16 bytes of parameters. So the linker would be quite happy with you as long as you give it a function named WinMain with 16 bytes of parameters.
If you wanted a console app, this is your indication that you messed something up.
You declared a pointer-to-function named main, and the linker warned you that this wouldn't work.
The _WinMain message has to do with how Windows programs work. Below the level of the C runtime, a Windows executable has a WinMain.
Try redefining it as int main(int argc, char *argv[])
What you have is a linker error. The linker expects to find a function with that "signature" - not void with no parameters
See http://publications.gbdirect.co.uk/c_book/chapter10/arguments_to_main.html etc
In listing 1, you are saying "There's a main() defined elsewhere in my code --- I promise!". Which is why it compiles. But you are lying there, which is why the link fails. The reason you get the missing WinMain16 error, is because the standard libraries (for Microsoft compiler) contain a definition for main(), which calls WinMain(). In a Win32 program, you'd define WinMain() and the linker would use the library version of main() to call WinMain().
In Listing 2, you have a symbol called main defined, so both the compiler & the linker are happy, but the startup code will try to call the function that's at location "main", and discover that there's really not a function there, and crash.
1.) An (compiler/platform) dependent function is called before code in main is executed and hence your behavior(_init in case of linux/glibc).
2) The code crash in 2nd case is justified as the system is unable to access the contents of the symbol main as a function which actually is a function pointer pointing to arbitrary location.
I'm using Delphi to make an XLL add-in for Excel, which involves making a lot of calls to the Excel4v function of xlcall32.dll. However, as I'm guessing very few Delphi experts here have worked with that specific API, I'm hoping that the problem might have been observed in other APIs too.
In C, specifically in the xlcall.h file that comes with the Microsoft Excel 2007 XLL SDK, Excel4v is defined as:
int pascal Excel4v(int xlfn, LPXLOPER operRes, int count, LPXLOPER opers[]);
In Delphi I'm using:
function Excel4v(xlfn: Integer; operRes: LPXLOPER; count: Integer;
opers: array of LPXLOPER): Integer; stdcall; external 'xlcall32.dll';
LPXLOPER is a pointer to a struct (in C) or record (in Delphi).
I've been doing my homework on declaring C functions in Delphi (this excellent article was a great help), and I think I'm declaring Excel4v properly. However, calls from Delphi code into that function cause exceptions ("access violation..." is what I keep seeing) unless they are followed by the following line:
asm pop sink; end;
Where "sink" is defined somewhere as an integer.
I have no clue about assembly... So there's no way would I have thought to try fixing the exceptions with "asm pop sink; end;". But "asm pop sink; end;" does indeed fix the exceptions. I first saw it used in this useful article on making XLLs using Delphi. Here's the most relevant quote:
"From Delphi the big stumbling block
with add-ins is the extra parameter
after the return address on the stack.
This comes free with every call to
Excel. I’ve never found out what it
holds, but so long as you throw it
away, your add-in will work fine. Add
the line asm pop variable, end; after
every call where variable can be any
global, local or object variable that
is at least 4 bytes long- integer is
fine. To repeat- THIS MUST BE INCLUDED
after every Excel4v call. Otherwise
you are constructing a time-bomb."
Basically I want to understand what's actually happening, and why. What could be causing a Win32 function to return an "extra parameter after the return address on the stack", and what does that actually mean?
Might there be another way to fix this, e.g. with a different compiler option or a different way of declaring the function?
And is there anything risky about calling "asm pop sink; end;" after every call to Excel4v...? It seems to work fine, but, as I don't understand what's going on, it feels a little dangerous...
I don't believe it's pascal vs stdcall - they are very similar calling conventions and should not result in a mismatched stack on function exit.
From the referenced article,
This would indeed be a very nice
syntax, but it is not the same as the
above array definition. Array-of
parameters are open array parameters.
They may look like any array, and they
do accept any array, but they get an
extra (hidden) parameter, which holds
the highest index in the array (the
High value). Since this is only so in
Delphi, and not in C or C++, you'd
have a real problem. (See also my
article on open arrays), since the
real number of parameters wouldn't
match.
You're getting the extra "highest array index" parameter being passed to the function. This is an int and has to be cleaned up when the function exits so that you don't wind up with a corrupted stack and crash. The article indicates how to pass arrays to C functions.
Something like:
type
PLPXLOPER = ^LPXLOPER;
And pass PLPXLOPER as the last parameter.
Your calling convention is wrong, specifically the "stdcall". The C declaration is specified as "pascal"
Stdcall passes parameters in right to left order, expects the routine to clean up, and does not use registers. Pascal, OTOH passes parameters in left to right order. Therefore, things are not happening the way the other half of the code expects in either case.
Change your Delphi declaration to also be "pascal" instead of "stdcall".
Most Windows functions use __stdcall for their calling conventions.