How to tell valgrind to prepend the stack frames with the binary names (executable, shared lib)? - valgrind

I get:
==830== at 0x4CD40DC: DebugSyslogHandlerFunc(DebugContext const&) (DebugSyslogHandler.cpp:202)
==830== by 0x6A2F3: AssertHandler::~AssertHandler() (Debug.hpp:1219)
==830== by 0x77F03: CircularQueue::capoffData(int) (CircularQueue.hpp:1216)
I want:
==830== at 0x4CD40DC: /usr/local/lib/shared_lib1.so.0: DebugSyslogHandlerFunc(DebugContext const&) (DebugSyslogHandler.cpp:202)
==830== by 0x6A2F3: /usr/local/lib/shared_lib2.so.0: AssertHandler::~AssertHandler() (Debug.hpp:1219)
==830== by 0x77F03: /usr/local/bin/my_exe: CircularQueue::capoffData(int) (CircularQueue.hpp:1216)
(after every address there is the binary path and name).
I fail to find anything like that.
How to tell valgrind to prepend the stack frames with the binary names (executable, shared lib)?

There is no way to instruct valgrind to always output the object name.
If valgrind finds the source location, then it does not output the object name.
The change to always output the object name is however trivial:
Adding the below marked lines (untested) in debuginfo.c should work
if (know_srcloc) {
if (know_objname) { // Add from here
APPEND(" (in "); //
APPEND(buf_obj); //
APPEND(")"); //
} // Till here
APPEND(" (");

Related

Check a kernel extension is loaded

I have to implement a function that installs a new kernel extension in the system. Before installing the extension I want to check whether it is already installed from another location. Since I do not know the other location I cannot use the sysconfig library function.
I've checked
truss genkex
to see how this is done by another tool. The only system call that was a bit interesting was read_sysconfig. Unfortunately I did not find documentation.
Any ideas?
Here I have an example function, that prints all loaded kernel extensions:
#define BUFF_SIZE 10241024U
static void testExtension() {
void *buffer = calloc( 1, BUFF_SIZE );
if( buffer ) {
struct ld_info *xInfo;
int result = loadquery(L_GETKERNINFO, buffer, BUFF_SIZE);
xInfo = buffer;
while( xInfo ) {
printf( ">>>>>>> >%s< %d\n", xInfo->ldinfo_filename, result );
uint offset = xInfo->ldinfo_next;
xInfo = offset ? (char*)xInfo + offset : NULL;
}
free( buffer );
}
}
The function you search for is SYS_QUERYLOAD sysconfig operation and here you can find more information about it
The SYS_QUERYLOAD sysconfig operation performs a query operation to
determine if a given object file has been loaded. This object file is
specified by the path field in the cfg_load structure passed in with
the parmp parameter. This operation utilizes the same cfg_load
structure that is specified for the SYS_KLOAD (SYS_KLOAD sysconfig
Operation) operation.
If the specified object file is not loaded, the kmid field in the
cfg_load structure is set to a value of 0 on return. Otherwise, the
kernel module ID of the module is returned in the kmid field. If
multiple instances of the module have been loaded into the kernel, the
module ID of the one most recently loaded is returned.
The libpath field in the cfg_load structure is not used for this
option.
Also you can check with this script about the objects in odm database.
for i in 1 2 3
do
odmget -q phase=$i Config_Rules
done
And check the file /sbin/rc.boot (which may contain load of some module(s)

Exporting TASKLET in kernel module?

I got two kernel modules which both exports some symbols using EXPORT_SYMBOL().
One of them exports basic function (sv1<-sv2) and it works but I got problem with the other one (sv1->sv2).
What I want is to export TASKLET. I read somewhere that is possibile and there is no proscription of doing this. Module nr 1 (called sv1) consists of BH Function and declaration of tasklet:
struct tasklet_struct sv_takslet;
EXPORT_SYMBOL(sv_takslet);
void sv_tasklet_function( unsigned long data )
{
printk( "%s\n", (char *)data );
return;
}
static int __init sv_publisher_init(void)
{
...
tasklet_init(&sv_takslet, &sv_tasklet_function,&sv_tasklet_data);
...
}
In second module there is global reference and task_schedule() function used at initialization of the module nr 2 (called sv2):
extern struct tasklet_struct sv_takslet;
...
tasklet_schedule(&sv_takslet);
The problem is when I got:
tasklet_schedule(&sv_takslet);
in my code I do not see my two modules on list (modprobe -l), but when I comment this line on sv2- they magically appear.
What could be a cause of that behavior? Is this initialization is correct?
EDIT
The cause of this problem is that module sv2 is loading before sv1 and has no knowledge about the tasklet (line: extern struct tasklet_struct sv_takslet). When I change destination that sv2 exports TASKLET to sv1 the problem is gone.
But now I am facing with that both modules have to export symbols to each other. I have no idea how to solve this problem...
Both *.c files are in the same directory and my Makefile has following line:
obj-m += sv_publisher.o zsv_core.o
Does anybody have some tips how to go about it?

Find out how many arguments a block needs

Let's say I have an array containing Blocks, and I need to assert that all of them expect a given number of arguments.
Is there a way to find this out programmatically?
This is indeed possible, for any recent version of Clang.
The Apple ABI for Blocks is private but also published. Since that document tells us the layout the compiler will use for a Block object, we can duplicate that information in a header file and use it to access the components of a Block.
Mike Ash's MABlockForwarding project does just that (see also the article) -- much of the stuff at the top of this file is a copy-paste from the ABI doc. The thing that he created which we are interested in is the BlockSig() function:
static const char *BlockSig(id blockObj)
{
struct Block *block = (__bridge void *)blockObj;
struct BlockDescriptor *descriptor = block->descriptor;
assert(block->flags & BLOCK_HAS_SIGNATURE);
int index = 0;
if(block->flags & BLOCK_HAS_COPY_DISPOSE)
index += 2;
return descriptor->rest[index];
}
which will return (for Blocks that have it (which they all do with recent Clang)), a type encoding string describing the Block's return and argument types. From there, you can create an NSMethodSignature object, and ask it for its numberOfArguments:
NSString * (^block)(int, NSArray *) = ^NSString * (int i, NSArray * a){
return #"Oh, yeah!";
};
const char * types = BlockSig(block);
NSMethodSignature * sig = [NSMethodSignature signatureWithObjCTypes:types];
[sig numberOfArguments];
The result there is 3, because it includes a hidden argument for the Block itself (and Blocks don't use the hidden _cmd argument or it would be 4).
The answer is you cannot. See the comment on Mike Ash's page regarding this:
Search for Intropection which sends you here
So, what is your real problem? If you structure the arguments properly, you can insure that your system functions properly. For instance, you can do what C++ does with default values for arguments, and cast each block to a type that takes the max number of args, and always push that many items on the stack. Or you could always have the first argument be the number of arguments you are pushing on the stack. If you push objects and not numbers/pointers, then you r blocks can look at the class of each argument and dynamically adapt.

Symbian: kern-exec 3 panic on RLibrary::Load

I have troubles with dynamic loading of libraries - my code panics with Kern-Exec 3. The code is as follows:
TFileName dllName = _L("mydll.dll");
TFileName dllPath = _L("c:\\sys\\bin\\");
RLibrary dll;
TInt res = dll.Load(dllName, dllPath); // Kern-Exec 3!
TLibraryFunction f = dll.Lookup(1);
if (f)
f();
I receive panic on TInt res = dll.Load(dllName, dllPath); What can I do to get rid of this panic? mydll.dll is really my dll, which has only 1 exported function (for test purposes). Maybe something wrong with the DLL? Here's what it is:
def file:
EXPORTS
_ZN4Init4InitEv # 1 NONAME
pkg file:
#{"mydll DLL"},(0xED3F400D),1,0,0
;Localised Vendor name
%{"Vendor-EN"}
;Unique Vendor name
:"Vendor"
"$(EPOCROOT)Epoc32\release\$(PLATFORM)\$(TARGET)\mydll.dll"-"!:\sys\bin\mydll.dll"
mmp file:
TARGET mydll.dll
TARGETTYPE dll
UID 0x1000008d 0xED3F400D
USERINCLUDE ..\inc
SYSTEMINCLUDE \epoc32\include
SOURCEPATH ..\src
SOURCE mydllDllMain.cpp
LIBRARY euser.lib
#ifdef ENABLE_ABIV2_MODE
DEBUGGABLE_UDEBONLY
#endif
EPOCALLOWDLLDATA
CAPABILITY CommDD LocalServices Location MultimediaDD NetworkControl NetworkServices PowerMgmt ProtServ ReadDeviceData ReadUserData SurroundingsDD SwEvent TrustedUI UserEnvironment WriteDeviceData WriteUserData
source code:
// Exported Functions
namespace Init
{
EXPORT_C TInt Init()
{
// no implementation required
return 0;
}
}
header file:
#ifndef __MYDLL_H__
#define __MYDLL_H__
// Include Files
namespace Init
{
IMPORT_C TInt Init();
}
#endif // __MYDLL_H__
I have no ideas about this... Any help is greatly appreciated.
P.S. I'm trying to do RLibrary::Load because I have troubles with static linkage. When I do static linkage, my main program doesn't start at all. I decided to check what happens and discovered this issue with RLibrary::Load.
A KERN-EXEC 3 panic is caused by an unhandled exception (CPU fault) generated by trying to invalidly access a region of memory. This invalid memory access can be for both code (for example, bad PC by stack corruption) or data (for example, accessing freed memory). As such these are typically observed when dereferencing a NULL pointer (it is equivalent to a segfault).
Certainly the call to RLibrary::Load should never raise a KERN-EXEC 3 due to programmatic error, it is likely to be an environmental issue. As such I have to speculate on what is happening.
I believe the issue that is observed is due to stack overflow. Your MMP file does not specify the stack or heap size the initial thread should use. As such the default of 4Kb (if I remember correctly) will be used. Equally you are using TFileName - use of these on the stack is generally not recommended to avoid... stack overflow.
You would be better off using the _LIT() macro instead - this will allow you to provide the RLibrary::Load function with a descriptor directly referencing the constant strings as located in the constant data section of the binary.
As a side note, you should check the error value to determine the success of the function call.
_LIT(KMyDllName, "mydll.dll");
_LIT(KMyDllPath, "c:\\sys\\bin\\");
RLibrary dll;
TInt res = dll.Load(KMyDllName, MyDllPath); // Hopefully no Kern-Exec 3!
if(err == KErrNone)
{
TLibraryFunction f = dll.Lookup(1);
if (f)
f();
}
// else handle error
The case that you can't use static linkage should be a strong warning to you. It shows that there is something wrong with your DLL and using dynamic linking won't change anything.
Usually in these cases the problem is in mismatched capabilities. DLL must have at least the same set of capabilities that your main program has. And all those capabilities should be covered by your developer cert.

Why does DTrace give me invalid-address errors sometimes but not always?

My program:
typedef struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
char *name;
long version;
long info;
long instance_size;
void *ivars;
void *methodLists;
void *cache;
void *protocols;
} *Class;
struct objc_object {
Class isa;
};
/* Code to extract the class name from arg0 based on a snippet by Bill Bumgarner: http://friday.com/bbum/2008/01/26/objective-c-printing-class-name-from-dtrace/ */
objc$target:NSObject:-init:entry {
printf("time: %llu\n", timestamp);
printf("arg0: %p\n", arg0);
obj = (struct objc_object *)copyin(arg0, sizeof(struct objc_object));
printf("obj: %p\n", obj);
printf("obj->isa: %p\n", obj->isa);
isa = (Class)copyin((user_addr_t)obj->isa, sizeof(struct objc_class));
printf("isa: %p\n", obj->isa);
classname = copyinstr((user_addr_t)(isa->name));
printf("classname: %s\n", classname);
}
Some output:
dtrace: script 'test.d' matched 1 probe
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28
dtrace: error on enabled probe ID 1 (ID 61630: objc5936:NSObject:-init:entry): invalid address (0x90206b98) in action #8 at DIF offset 28
CPU ID FUNCTION:NAME
0 61630 -init:entry time: 28391086668386
arg0: 1291ae10
obj: 6f0a1158
obj->isa: a023f360
isa: a023f360
classname: NSBitmapImageRep
1 61630 -init:entry time: 28391586872297
arg0: 12943560
obj: 6f4a1158
obj->isa: 2fca0
isa: 2fca0
classname: GrowlApplicationTicket
1 61630 -init:entry time: 28391586897807
arg0: 152060
obj: 6f4a1280
obj->isa: 2fe20
isa: 2fe20
classname: GrowlNotificationTicket
2 61630 -init:entry time: 28391079142905
arg0: 129482d0
obj: 700a1128
obj->isa: a0014140
isa: a0014140
classname: NSDistributedObjectsStatistics
2 61630 -init:entry time: 28391079252640
arg0: 147840
obj: 700a1250
obj->isa: a0014780
isa: a0014780
classname: NSDistantObjectTableEntry
Why the errors? It seems to be the class name (that's the only %s, and I don't get any errors if I remove it), but why does it think some classes' names are invalid pointers?
Is there any way to get the error messages to actually tell me which line of my DTrace program caused a problem?
Is there a way to call object_getClassName instead of doing this structure-inspection dance?
For what it's worth, the program I'm tracing works fineā€”it's not crashing, so I don't believe that the classes really are broken.
Colin is pretty close to correct.
See:
http://www.friday.com/bbum/2008/01/03/objective-c-using-dtrace-to-trace-messages-to-nil/
More likely than not, you need to set the DYLD_SHARED_REGION environment variable to avoid. dtrace only really works against mapped memory that is actually resident in physical memory.
You can figure out what is missing by using the vmmap command line tool.
Do a vmmap PID on your application after the above failure messages are generated. Looking at the output, see what region the addresses like 0x90206b98 fall into. Given that address, it is likely in a non-writeable shared chunk of memory that probably isn't resident and, thus, dtrace can't read from it.
This error happens when copyin / copyinstr is used on a page that's not faulted in yet. A common workaround is to let the function use the data in question, and then copyin[str] in a :::return clause. For example:
syscall::open:entry
{
self->filename = arg0; /* Hang on to the file name pointer. */
}
syscall::open:return
/self->filename/
{
#files[copyinstr(self->filename)] = count();
self->filename = 0;
}
END
{
trunc(#files, 5);
}
I haven't entirely tracked this down myself. It's possible that DTrace is trying to resolve some Objective-C symbols. Although DTrace is a dynamic tracing facility it doesn't mesh well with Objective-C dynamically loading things at runtime. When Objective-C does load new classes,etc DTrace has to resolve this and it takes a little time, especially when your app is just starting up. Even if it does get things loaded, and your objc app is still loading new classes onto the objc runtime its possible DTrace could get screwed up and print methods in the wrong order (if you care about seeing the correct order methods are being executed in), print incorrect timing results,etc.
This is my best guess based on the information provided.
DTrace was purposefully designed in such a way as to make DTrace scripts as deterministic as possible. This is why there are no if statements, loops, subroutines (other than the pseudo-subroutines provided by DTrace itself), etc. This is because the code in your DTrace script is running in kernel mode, not user-land as part of the process(es) being traced. In general, the information DTrace has access to is "read-only" (like most generalizations, this is not strictly true), being able to twiddle bits in programs, or the kernel, with something as powerful as DTrace can cause things to go very, very wrong, very very quickly.
Dollars to donuts, the problem you're having is because the page that the pointer points to is not mapped in to core by the VM system. DTrace can only examine information for memory that is in core- it can't double-fault to get the VM system to load in the page.
You can probably help alleviate the problem if you've got an idea of what the classes "should" be and forcing the pages to be mapped in to core by doing a bunch of dummy NSLog() statements that reference the needed classes at some convenient point early in your programs start up.