Developing multithreaded programs to examine and modify pthread library objects

The pthread debug library (libpthdebug.a) provides a set of functions that enable application developers to examine and modify pthread library objects.

This library can be used for both 32-bit applications and 64-bit applications. This library is threadsafe. The pthread debug library contains a 32-bit shared object and a 64-bit shared object.

The pthread debug library provides applications with access to the pthread library information. This includes information on pthreads, pthread attributes, mutexes, mutex attributes, condition variables, condition variable attributes, read/write locks, read/write lock attributes, and information about the state of the pthread library.

Note: All data (addresses, registers) returned by this library is in 64-bit format both for 64-bit and 32-bit applications. It is the application's responsibility to convert these values into 32-bit format for 32-bit applications. When debugging a 32-bit application, the top half of addresses and registers is ignored.

The pthread debug library does not report information on mutexes, mutex attributes, condition variables, condition variable attributes, read/write locks, and read/write lock attibutes that have the pshared value of PTHREAD_PROCESS_SHARED.

Initialization

The application must initialize a pthread debug library session for each pthreaded process. The pthdb_sessison_init function must be called from each pthreaded process after the process has been loaded. The pthread debug library supports one session for a single process. The application must assign a unique user identifier and pass it to the pthdb_session_init function, which in turn assigns a unique session identifier that must be passed as the first parameter to all other pthread debug library functions, except pthdb_session_pthreaded function, in return. Whenever the pthread debug library invokes a call back function, it will pass the unique application assigned user identifier back to the application. The pthdb_session_init function checks the list of call back functions provided by the application, and initializes the session's data structures. Also, this function sets the session flags. An appplication must pass the PTHDB_FLAG_SUSPEND flag to the pthdb_session_init Function. See the pthdb_session_setflags function for a full list of flags.

Call back functions

The pthread debug library uses the call back functions to obtain and write data, as well as to give storage management to the application. Required call back functions for an application are as follows:
read_data
Retrieves pthread library object information
alloc
Allocates memory in the pthread debug library
realloc
Reallocates memory in the pthread debug library
dealloc
Frees allocated memory in the pthread debug library
Optional call back functions for an application are as follows:
read_regs
Necessary only for the pthdb_pthread_context and pthdb_pthread_setcontext subroutines
write_data
Necessary only for the pthdb_pthread_setcontext subroutine
write_regs
Necessary only for pthdb_pthread_setcontext subroutine

Update function

Each time the application is stopped, after the session has been initialized, it is necessary to call the pthdb_session_update function. This function sets or resets the lists of pthreads, pthread attributes, mutexes, mutex attributes, condition variables, condition variable attributes, read/write locks, read/write lock attributes, pthread specific keys, and active keys. It uses call back functions to manage memory for the lists.

Context functions

The pthdb_pthread_context function obtains the context information, and the pthdb_pthread_setcontext function sets the context. The pthdb_pthread_context function obtains the context information of a pthread from either the kernel or the pthread data structure in the application's address space. If the pthread is not associated with a kernel thread, the context information saved by the pthread library is obtained. If a pthread is associated with a kernel thread, the information is obtained from the application using the call back functions. The application must determine if the kernel thread is in kernel mode or user mode and then to provide the correct information for that mode.

When a pthread with kernel thread is in kernel mode, you cannot get the full user mode context because the kernel does not save it in one place. The getthrds function can be used to obtain part of this information, because it always saves the user mode stack. The application can discover this by checking the thrdsinfo64.ti_scount structure. If this is non-zero, the user mode stack is available in the thrdsinfo64.ti_ustk structure. From the user mode stack, it is possible to determine the instruction address register (IAR) and the call back frames, but not the other register values. The thrdsinfo64 structure is defined in procinfo.h file.

List functions

The pthread debug library maintains lists for pthreads, pthread attributes, mutexes, mutex attributes, condition variables, condition variables attributes, read/write locks, read/write lock attributes, pthread specific keys and active keys, each represented by a type-specific handle. The pthdb_object functions return the next handle in the appropriate list, where object is one of the following: pthread, attr, mutex, mutexattr, cond, condattr, rwlock, rwlockattr or key. If the list is empty or the end of the list is reached, PTHDB_INVALID_OBJECT is reported, where OBJECT is one of the following: PTHREAD, ATTR, MUTEX, MUTEXATTR, COND, CONDATTR, RWLOCK, RWLOCKATTR or KEY.

Field functions

Detailed information about an object can be obtained by using the appropriate object member function, pthdb_object_field, where object is one of the following: pthread, attr, mutex, mutexattr, cond, condattr, rwlock, rwlockattr or key and where field is the name of a field of the detailed information for the object.

Customizing the session

The pthdb_session_setflags function allows the application to change the flags that customize the session. These flags control the number of registers that are read or written during context operations.

The pthdb_session_flags function obtains the current flags for the session.

Terminating the session

At the end of the session, the session data structures must be deallocated, and the session data must be deleted. This is accomplished by calling the pthdb_session_destroy function, which uses a call back function to deallocate the memory. All of the memory allocated by the pthdb_session_init, and pthdb_session_update functions will be deallocated.

Example of connecting to the pthread debug library

The following example shows how an application can connect to the pthread debug library:
/* includes */

#include <thread.h>
#include <ys/pthdebug.h>

...

int my_read_data(pthdb_user_t user, pthdb_symbol_t symbols[],int count)
{
  int rc;

  rc=memcpy(buf,(void *)addr,len);                              
  if (rc==NULL) {                                               
    fprintf(stderr,&odq;Error message\n&cdq;);
    return(1);                                                  
  }                                                             
  return(0);                                                    
}
int my_alloc(pthdb_user_t user, size_t len, void **bufp)
{
  *bufp=malloc(len);                                            
  if(!*bufp) {                                                  
    fprintf(stderr,&odq;Error message\n&cdq;);
    return(1);                                                  
  }                                                             
  return(0);                                                    
}
int my_realloc(pthdb_user_t user, void *buf, size_t len, void **bufp)
{
  *bufp=realloc(buf,len);                                    
  if(!*bufp) {                                               
    fprintf(stderr,“Error message\n”);
    return(1);                                               
  }                                                          
  return(0);                                                 
}
int my_dealloc(pthdb_user_t user,void *buf)
{
  free(buf); 
  return(0); 
}

status()
{
  pthdb_callbacks_t callbacks =
                    {  NULL,                
                       my_read_data,  
                       NULL, 
                       NULL,                
                       NULL,                
                       my_alloc,            
                       my_realloc,          
                       my_dealloc,          
                       NULL                 
                    };

  ...

  rc=pthread_suspend_others_np();
  if (rc!=0)
    deal with error

  if (not initialized)
    rc=pthdb_session_init(user,exec_mode,PTHDB_SUSPEND|PTHDB_REGS,callbacks,
                          &session);
    if (rc!=PTHDB_SUCCESS)
       deal with error

  rc=pthdb_session_update(session);
  if (rc!=PTHDB_SUCCESS)
        deal with error
  
   retrieve pthread object information using the object list functions and 
   the object field functions

  ...
  
  rc=pthread_continue_others_np();
  if (rc!=0)
    deal with error
}

...

main()
{
  ...
}