How to read the function parameters from call stack frames programmatically in Windows?
Asked Answered
U

1

10

I was trying to walk through the call stack frames and extract some information from them. I am able to extract the file names, line numbers, and function names by using StackWalk64 , SymGetSymFromAddr64, and SymGetLineFromAddr64 APIs from WinDBG.

However, the DWORD64 Params[4] in STACKFRAME64, which is a return value from StackWalk64, only supports reading back four 64 bits function parameters from a frame. Even worse, on 32-bit system, only the lower 32 bits of Params[4] are used, so a single parameter with more than 32 bits needs two or more elements.

typedef struct _tagSTACKFRAME64 {
  ADDRESS64 AddrPC;
  ADDRESS64 AddrReturn;
  ADDRESS64 AddrFrame;
  ADDRESS64 AddrStack;
  ADDRESS64 AddrBStore;
  PVOID     FuncTableEntry;
  DWORD64   Params[4];
  BOOL      Far;
  BOOL      Virtual;
  DWORD64   Reserved[3];
  KDHELP64  KdHelp;
} STACKFRAME64, *LPSTACKFRAME64;

I couldn't find any API to read ALL the parameters from a stack frame without limitation.

I was thinking to use ebp/rbp to extract the values from the stack (x86/x64) and the registers (x64). But still, only the "possible" values of the parameters can be obtained if I do this.

Is there any API I could use to get the accurate values? It would be even better if I can get the type and name of the parameters.

Ugly answered 17/4, 2014 at 22:16 Comment(12)
Why the downvote? This seems like a reasonable question.Preside
You cannot get accurate values because the compiler is free to optimize its parameter usage in a manner such that the original parameters are no longer stored on the stack. (For example, on x64, parameters are passed in registers and may never actually get written to the stack.) The values you get from STACKFRAME64 is a best effort.Belshin
@RaymondChen: Correct, but I can't think of a reason such an API couldn't exist. A variant of SymGetSymFromAddr64 where you'd give it a stackframe and a parameter index, instead of just a pointer.Dehypnotize
SymGetSymFromAddr64 gives you the symbol name of the function itself, which is a mangled C++ name. If you run that through a demangler, you can derive the parameter types, though knowing the type alone probably isn't enough to interpret the Params member. But I think that's as close as you're going to get.Dehypnotize
@MooingDuck: Thanks for info. Yes looks like demangle the symbol name and then try to interpret the parameters from registers (x64) and stack is the best solution for now... Still wait to see if any solution from API side.Ugly
Also, on a 32bit systems, parameters could only be 32 bits. A single parameter with more than 32 bits was split into 32 bit chunks. So the Params is correct, as that's exactly what's happening under-the-hood, and it has no way to know to combine them.Dehypnotize
If you know the function's calling convention and parameter types (which demangling might tell you), you have a chance of reverse engineering how a compiler would pass those parameters, since many calling conventions are well-defined and easy to find specs on.Material
The reason such an API couldn't exist is the reason @RaymondChen gave. The operating system doesn't know what the compiler has done.Coachandfour
The parameter may not even exist any more. For example, if the parameter is not used after line 10, the compiler may reuse the memory for something else. You call another function at line 14, then ask "What is the value of parameter 2?' The answer is "That information no longer exists."Belshin
@RaymondChen: Then any idea about how the MSVC and WinDBG implements the parameter values displaying? Is there any "hidden" APIs?Ugly
Not even MSVC and WinDBG can get the parameters if they no longer exist.Belshin
@user3199553 i can't find a definite answer but believe you need to create a IMAGEHLP_STACK_FRAME (either by hand from other structures or by some api that i could not find), then you can use SymSetContext and SymEnumSymbols to find all the (visible if not optimized) function arguments. that will hive you a pointer to SYMBOL_INFO structure that you can use to get all the information you want.Epperson
W
1

There is no API for it. Why should there be any, modern OSes are not interested in some folks playing with this stuff. As said earlier, the compiler is free to make optimizations so you can't have any deterministic tool to do it. But, there are heuristics! You can know how much parameters are in function if you parse assembly before the call or ret after the call, you always have return address which you can check if it is in CS.

Above all - you should read about term 'stack unwinding'.

Warm answered 2/5, 2014 at 12:43 Comment(1)
Almost -- unwind tables are a thing these days due to EH requirements, and those will need parameter data so that they can unwind pass-by-value parameters of non-trivial type.Alkalinize

© 2022 - 2024 — McMap. All rights reserved.