How do I print a CFStringRef in a DTrace action? - dtrace

I have a DTrace probe catching calls to a function, and one of the function's arguments is a CFStringRef. This is private structure that holds a pointer to a unicode string. But the CFStringRef is not itself a char*, so normal DTrace methods like copyinstr() just return ?cp?, which isn't exactly helpful.
So how can I print out the string in the DTrace action?

As far as I know, there is not built-in support for this kind of thing. Usually a library would publish a probe that decodes the string for you (as Brad mentions). So since in your case you can't modify the library, you'll need to use the pid provider and hook into a user function, and decode it yourself.
The solution (which is very similar to the approach you would use in C++ to dump a std::string) is to dump out the pointer which is stored at an 2 word offset from the base CFStringRef pointer. Note that since a CFString can store strings internally in a variety of formats and representations, this is subject to change.
Given the trivial test application:
#include <CoreFoundation/CoreFoundation.h>
int mungeString(CFStringRef someString)
{
const char* str = CFStringGetCStringPtr(someString, kCFStringEncodingMacRoman);
if (str)
return strlen(str);
else
return 0;
}
int main(int argc, char* argv[])
{
CFStringRef data = CFSTR("My test data");
printf("%u\n", mungeString(data));
return 0;
}
The following dtrace script will print the string value of the first argument, assuming it is a CFStringRef:
#!/usr/sbin/dtrace -s
/*
Dumps a CFStringRef parameter to a function,
assuming MacRoman or ASCII encoding.
The C-style string is found at an offset of
2 words past the CFStringRef pointer.
This appears to work in 10.6 in 32- and 64-bit
binaries, but is an implementation detail that
is subject to change.
Written by Gavin Baker <gavinb.antonym.org>
*/
#pragma D option quiet
/* Uncomment for LP32 */
/* typedef long ptr_t; */
/* Uncomment for LP64 */
typedef long long ptr_t;
pid$target::mungeString:entry
{
printf("Called mungeString:\n");
printf("arg0 = 0x%p\n",arg0);
this->str = *(ptr_t*)copyin(arg0+2*sizeof(ptr_t), sizeof(ptr_t));
printf("string addr = %p\n", this->str);
printf("string val = %s\n", copyinstr(this->str));
}
And the output will be something like:
$ sudo dtrace -s dump.d -c ./build/Debug/dtcftest
12
Called mungeString:
arg0 = 0x2030
string addr = 1fef
string val = My test data
Simply uncomment the right typedef depending on whether you are running against a 32-bit or 64-bit binary. I have tested this against both architectures on 10.6 and it works fine.

I believe that you can't do this directly, but you can create a custom static probe that feeds in the CFString / NSString as a char *, which you can use with copyinstr(). I describe how to do this in an article here.

Related

In Delphi, I send AnsiString Data to C++ DLL Function, but input value was lost. Why happened this situation?

I got to know a little bit more detailed issues. So, I changed Question.
Thanks to people who previous question about the answered.
Now, It is a detailed question.
In delphi, I send data of AnsiString type to C++ Function in DLL
In Delphi07
TFunctionA = function (aHandle: FunctionAHANDLE ; input: AnsiString): AnsiString; cdecl;
....
FunctionA('Test string value');
In C++ DLL
char * FunctionA(char *input){
....
return pReturn;
};
In situation, I confirmed data(char *input) using Visual Studio 15 Debug, the data was lost(AnsiString)
But In Delphi, TFunctionA's Return type change AnsiString to AnsiChar,
and then data(char *input) is transmitted("Test string value").
TFunctionA = function (aHandle: FunctionAHANDLE ; input: AnsiString): AnsiChar; cdecl;
I don't know this situation because, I have never worked with Delphi.
Delphi's AnsiString is similar but definitely not the same thing as C's char *. Assuming your C function is:
char * FunctionA(char *input){
....
return pReturn;
};
Then your Delphi declaration should look like this:
function FunctionA(Input: PAnsiString): PAnsiString; cdecl;
And you would use it in this fashion:
var
SomeInput, SomeOutput: AnsiString;
begin
SomeInput := 'foobar';
SomeOutput := AnsiString(FunctionA(PAnsiChar(SomeInput)));
Writeln(SomeOutput);
end;
Here you first "convert" (not really, but close enough) AnsiString SomeInput to PAnsiChar, which is a zero-terminated string exactly equal to C's char *. You pass that to your C function, then convert (really) the char * result (same thing as Delphi's PAnsiChar) to Delphi's AnsiString.
Or, if you want to explain it in C/C++ terms, you have a C++ string which you can "convert" to char * using string::c_str(), and then you create a new string based on a char * thanks to a string(char *) constructor.

Returning the address of a char* variable

I'm currently developing a project and in one of my functions, I need to return the address of a char* variable.
Or maybe it's better to return the address of my string, but I don't know how to do this.
This is my code:
const char* rogner(){
int tableauXY[2];
tableauXY[0]=5;
tableauXY[1]=8;
string valeurs=to_string(tableauXY[0])+";"+to_string(tableauXY[1]);
const char* val1=valeurs.c_str();
return val1;
}
There are several ways to export string from extern "C" function:
1) Provide the second method to free release memory allocated:
extern "C" const char* getStr(...)
{
auto result = new char[N];
...
return result;
}
extern "C" void freeStr(const char* str)
{
delete[] const_cast<char*>(str);
}
2) Use OS allocator, e.g. in case of Windows:
// Client must call SysFreeString later
extern "C" const char* getStr(...)
{
auto result = SysAllocString(N);
...
return result;
}
3) Use client-provided buffer (there are a lot of variations how to tell the client what size buffer should have).
extern "C" int getStr(char* buffer, int bufSize, ...){}
There are many answers to your question. But one thing you can't do is return the address of a local variable. Returning the address of a local variable is undefined behavior, so forget about that option completely.
Since you stated that the function is part of a DLL, then it is better to use the "standard" ways to handle strings between a DLL and the client application.
One usual and widely used method is to have the client create the char buffer, and have the char buffer passed to you. Your function then fills in the user-supplied buffer with the information. Optional items such as size of the buffer can also be passed.
The above method is used by most functions in the Windows API that requires passing and returning strings.
Here is a small example:
#include <algorithm>
//...
char *rogner(char *buffer, int buflen)
{
int tableauXY[2];
tableauXY[0]=5;
tableauXY[1]=8;
string valeurs=to_string(tableauXY[0])+";"+to_string(tableauXY[1]);
// get length of buffer and make sure we copy the correct
// number of characters
size_t minSize = std::min(buflen, valeurs.length());
const char* val1=valeurs.c_str();
memcpy(buffer, val1, minSize);
// return the user's buffer back to them.
return buffer;
}
There are variations to the above code, such as
returning the number of characters copied instead of the original buffer.
If buflen==0, only return the total number of characters that would be copied. This allows the client to call your function to get the number of characters, and then call it a second time with
the buffer of the appropriate size.
Thanks for all, it works
I've used the PaulMcKenzie's method and it's good!
I have not tried the Nikerboker's solution so maybe it works too.
Thanks

Ctype in python

i have this C++ code in linux ubuntu i want use this method in python by ctype
but can not send parameter to ctype.cdl.funcion
C++ code :
extern "C" unsigned char* getuserdata(int code,unsigned char* globalkey,unsigned char* key)
{
unsigned char data[256];
KeyA *keya;
keya=new KeyA;
keya->OpenDevice(0);
keya->Init(globalkey,globalkey,globalkey,globalkey);
keya->ReadUserMemory( 0,256,key,data);
return data;
}
sample use this function in C++:
unsigned char g_user[16] = { 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22 };
unsigned char publickey[16] = { 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55 };
printf("function Return: %s\n", getuserdata(0,publickey,g_user));
and my python source code (not Worked!!) is :
from ctypes import *
dl=cdll.LoadLibrary('/home/iman/KCore/kcore/hkey.so');
dl.getuserdata.restype = c_char_p
string_buffers = [addressof(create_string_buffer(16)) ]
string_buffers[0]= "5555555555555555";
string_buffers2 = [addressof(create_string_buffer(16)) ]
string_buffers2[0]="2222222222222222";
st= dl.getuserdata(0,string_buffers,string_buffers2);
print st+"\n";
Let's look at the code...
string_buffers = [addressof(create_string_buffer(16)) ]
This line creates a Python list containing the address of a 16-byte string buffer (or maybe it's not bytes but characters, please find that out yourself).
string_buffers[0]= "5555555555555555";
This line replaces the pointer from above with the string "555555555555555".
dl.getuserdata(0,string_buffers,string_buffers2);
Here, you pass the list with a string to the function, while the function takes a pointer to bytes. Question is what you want to achieve here, i.e. whether you want the buffer to be written to or not. If not, use const in C++ and simply pass "22222" as parameter, ctypes will do the rest for you automatically.
That said, it could be that I'm guessing wrong, since you haven't explained what exactly is happening (quote the error messages!) and how exactly you determined that something doesn't work. Further, you should clean up your broken C++ code or temporarily replace it with something smaller that is more suitable to explain the exact problem.

In solaris vsnprintf core dump in strlen function is any method to resolve this?

I am calling vsnprintf , as below If Vargs is NULL then vsnprintf coredump in strlen function,but same core work fine in other OS like linux , AIX ....
Is there any solution for this ? I can't avoid passing NULL into varags , I want vsnprintf must not coredump ...
Code:
int example(char * buff,size_t count,const char format[],...)
{
va_list vargs = NULL;
va_start(vargs,format);
ret = vsnprintf(buff,count,format,vargs);
va_end(vargs);
return ret;
}
main()
{
char buff[100] = {0};
char *FileName = NULL;
ret = example(buff,100,"File Name is %s",FileName);
}
There are several solutions, but none is entirely trivial. Unfortunately, what you are finding is that SOME systems have a "catch" for NULL pointers in the handling of "%s", which fixes up the problem you are seeing. This is not required by the C standard.
The most simple (in terms of complexity of implementation) is to simply check the string before passing it into example, e.g. :
char *FileName = NULL;
if (!FileName) FileName = "(null)");
ret = example(buff,100,"File Name is %s",FileName);
or
char *FileName = NULL;
ret = example(buff,100,"File Name is %s",FileName?FileName:"(null)");
But if example is called a gazillion times in the code, it may be simpler to search for "%s" and check at that point if the value is NULL, and replace it. This gets quite messy, because you pretty much have to implement a full "%[flags][width][type]" parser for the printf formatting, and walk over the arguments. But there is a further problem here: You can't modify the va_list (it MAY work, but it's undefined behaviour), so you probably will end up writing your own vsnprintf function.
So, I would try to fix it at the source before going down the route of implementing your own function.

LoadLibrary taking a LPCTSTR

I want to develop a plugin system using LoadLibrary.
My problem is: I want my function to take a const char* and LoadLibrary takes a LPCTSTR.
I had the bright idea to do (LPCSTR)path which kept giving me a module not found error.
Current code is below. If I uncomment the widepath = L.. line it works fine. I've read solutions using MFC but I'd like to not use MFC.
Current code:
bool PluginLoader::Load(char *path)
{
path = "Release\\ExamplePlugin.dll";
LPCTSTR widepath = (LPCTSTR)path;
//widepath = L"Release\\ExamplePlugin.dll";
HMODULE handle = LoadLibrary(widepath);
if (handle == 0)
{
printf("Path: %s\n",widepath );
printf("Error code: %d\n", GetLastError());
return false;
}
int (*load_callback)() = (int (*)()) GetProcAddress(handle, "_plugin_start#0");
if (load_callback == 0)
{
return false;
}
return load_callback() == LOAD_SUCCESS;
}
Use LoadLibraryA(), it takes a const char*.
Winapi functions that take strings exist in two versions, an A version that takes an Ansi string and a W version that takes a wide string. There's a macro for the function name, like LoadLibrary, that expands to either the A or the W flavor, depending if UNICODE is #defined. You are compiling your program with that #define in effect, so you get LoadLibraryW(). Simply cheat and use LoadLibraryA() explicitly.
I suggest you using TCHAR and LoadLibrary instead of using manually char or wchar_t and LoadLibraryA or LoadLibraryW to make a generic application, both for UNICODE and ASCII characters.
So you could do:
TCHAR x[100] = TEXT("some text");
I suggest you reading this article. LPCTSTR is a const TCHAR*.
Why use LoadLibrary instead of LoadLibraryW or LoadLibraryA? To support both UNICODE and ASCII without creating two different programs, one to work with char and the other with wchar_t.
Also, take a look at what Microsoft says about it: Conventions for Function Prototypes
If you continue to use a char * for the parameter, you'll run into cases where an unusual character is used in the filename and the LoadLibrary will fail. Change the function to use wchar_t instead, and while you're at it make the parameter const since you're not modifying the string.
bool PluginLoader::Load(const wchar_t *path)
I think you'll find that LPCTSTR on 32-bit Windows is a macro that expands to const wchar_t * when the program options are set to Unicode.
The approved method with LoadLibrary is to not use a char const *, but instead use a TCHAR const *, and use the _T macro on all literals:
bool PluginLoader::Load(TCHAR const *path) {
path = _T("Release\\ExamplePlugin.dll");
HMODULE handle = LoadLibrary(path);
if (handle == 0)
{
_tprintf(_T("Path: %s\n"),widepath );
_tprintf(_T("Error code: %d\n"), GetLastError());
return false;
}
int (*load_callback)() = (int (*)()) GetProcAddress(handle, _T("_plugin_start#0"));
if (load_callback == 0)
{
return false;
}
return load_callback() == LOAD_SUCCESS;
}
This will automatically use LoadLibraryW when _UNICODE/UNICODE are defined, and LoadLibraryA when they're not. Likewise, _T will give narrow or wide string literals on the same basis, so it all stays in sync.
I generally prefer to use the W suffixed functions explicitly, and use the L prefix on string literals. Windows works almost exclusively with wide strings internally anyway, so the version A-suffixed versions that take narrow string literals are mostly small stubs that convert their arguments to wide strings, then call the wide string version. Using the wide string version directly saves both time and memory.
Narrow string support in Windows was originally there primarily for compatibility with the long-since defunct Windows 95/98/SE/Me line that lacked wide string support. Those have been gone for quite a while, so about the only reason to use narrow literals now is because that's what you're being supplied from some outside source.