Please enable JavaScript to view this site.

Bug Validator Help

Navigation: » No topics above this level «

NT Service API

Scroll Prev Top Next More

 

 

The Bug Validator stub service libraries

 

The NT Service API is very simple, consisting of functions to load, start and unload the Bug Validator DLL.

 

We have also provided some debugging functions to help you debug the implementation of the NT Service API because getting data into and out of services is not always straightforward.

 

The stub service libraries used for this are shown in the following table:

 


32 bit Bug Validator

32 bit service

svlBVStubService.lib

 

All the functions exported from these libraries are exported as extern "C" so that C and C++ users can use them.

 

The simple header file svlBVStubService.h and svlServiceError.h is found in the svlBVStubService directory of the install area.

 

The header files provides an error enumeration and the API functions.

 

API changes - February 2018

 

To make the API easier to use with services we changed the API by adding many debugging functions to allow you to easily log information. We also extended the error enumeration to provide additional error status values.

 

We also split the function of loading and starting the validator into two functions - a load function and a start function.

 

We split the functionality so that you could setup a service callback prior to calling the start function. The service callback allows the service control manager to be informed that the service is still active during time consuming operations, such as starting the validator when the service is non-trivial in scope. Failure to inform the service control manager results in the service being killed by the service control manager because it thinks the service has hung. This change in the API is to ensure you get better results from using our software.

 

What do you need to do to move from the old API to the new API?

 

Change all SVL_ERROR declarations to SVL_SERVICE_ERROR.

 

Your previous startup code probably looked like this:

 

   SVL_ERROR errCode;
 
   errCode = svlBVStub_LoadBugValidator();

 

Change it to this:

 

   SVL_SERVICE_ERROR errCode;
 
   errCode = svlBVStub_LoadBugValidator();
 
   errCode = svlBVStub_SetServiceCallback(serviceCallback, NULL);
 
   errCode = svlBVStub_StartBugValidator();

 

The serviceCallback would look something like this:

 

   void serviceCallback(void   *userParam)
   {
       static DWORD dwCheckPoint = 1;
   
       ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
       ssStatus.dwServiceSpecificExitCode = 0;
 
       ssStatus.dwControlsAccepted = 0;
      
       ssStatus.dwCurrentState = dwCurrentState;
       ssStatus.dwWin32ExitCode = dwWin32ExitCode;
       ssStatus.dwWaitHint = dwWaitHint;
       ssStatus.dwCheckPoint = dwCheckPoint++;
      
       // Report the status of the service to the service control manager.
 
       return SetServiceStatus(sshStatusHandle, &ssStatus);
   }

 

In the code above we have omitted error handling. To see how to use the new logging function with error handling please examine the source code service.cpp in the example service project.

 

Important.

 

Once your service is running (rather than starting) your service callback should set the appropriate running status SERVICE_RUNNING rather than SERVICE_START_PENDING.

An alternative solution is to prevent the service callback from being called once the service status has been set to running. Do this by calling svlCVStub_SetServiceCallback(NULL, NULL);.

 

API Reference

 

SVL_SERVICE_ERROR Enumeration

 

typedef enum _svlServiceError
{
   SVL_OK,                              // Normal behaviour
   SVL_ALREADY_LOADED,                  // Stub DLL already loaded into service
   SVL_LOAD_FAILED,                     // Failed to load stub DLL into service
   SVL_FAILED_TO_ENABLE_STUB_SYMBOLS,   // Loaded DLL, but failed to enable stub symbols because couldn't find function
   SVL_NOT_LOADED,                      // Couldn't unload DLL because DLL not loaded
   SVL_FAIL_UNLOAD,                     // Couldn't unload DLL because couldn't find function
   SVL_FAIL_TO_CLEANUP_INTERNAL_HEAP,   // Couldn't get the internal stub heap and thus couldn't clean it up
   SVL_FAIL_MODULE_HANDLE               // Couldn't get the stub DLL handle so couldn't continue
   SVL_FAIL_SETSERVICECALLBACK,         // Couldn't call the set service callback

   SVL_FAIL_COULD_NOT_FIND_ENTRY_POINT, // Couldn't find the DLL entry point to start the validator

   SVL_FAIL_TO_START                    // Failed to start the Validator

} SVL_SERVICE_ERROR;

 

The API consists of the following functions. Each function will be documented in detail after the list of functions.

 

extern "C" SVL_SERVICE_ERROR svlBVStub_LoadBugValidator();
 
extern "C" SVL_SERVICE_ERROR svlBVStub_LoadBugValidator6432();
 
extern "C" SVL_SERVICE_ERROR svlBVStub_StartBugValidator();
 
extern "C" SVL_SERVICE_ERROR svlBVStub_UnloadBugValidator();
 
extern "C" SVL_SERVICE_ERROR svlBVStub_SetServiceCallback(serviceCallback_FUNC callback,
                                                          void*                userParam);
 
// debugging functions
 
extern "C" void svlBVStub_setLogFileName(const wchar_t* fileName);
 
extern "C" void svlBVStub_deleteLogFile();
 
extern "C" void svlBVStub_writeToLogFileA(const char* text);
 
extern "C" void svlBVStub_writeToLogFileW(const wchar_t* text);
 
extern "C" void svlBVStub_writeToLogFile(SVL_SERVICE_ERROR errCode);
 
extern "C" void svlBVStub_writeToLogFileLastError(DWORD errCode);
 
extern "C" void svlBVStub_dumpPathToLogFile();

 

 

Loading the Bug Validator DLL into your service

 

To load the memory validator stub dll svlBugValidatorStub.dll into your service, use the function below, not LoadLibrary().

 

extern "C" SVL_SERVICE_ERROR svlBVStub_LoadBugValidator();

 

This loads the DLL and sets up a few internal variables in the DLL to ensure that symbols are sent from the stub to the Bug Validator user interface.

 

This is necessary because the Bug Validator user interface can't open a process handle to a service and so is unable to get symbols from the process.

 

To solve this, symbols are sent from the stub to the user interface as needed.

 

If you just call LoadLibrary() on the DLL, symbols will not be sent to the Bug Validator user interface and you won't get meaningful function names in your stack traces.

 

This function can be used when monitoring:

 

32 bit services or applications with Bug Validator.

 

 

Which function you should call is shown in the table below.

 


32 bit Bug Validator

32 bit service

svlBVStub_LoadBugValidator()

 

 

Unloading the Bug Validator DLL from your service.

 

Similarly to the loading, you'll need to use the following to unload the memory validator stub dll, and not FreeLibrary().

 

extern "C" SVL_SERVICE_ERROR svlBVStub_UnloadBugValidator();

 

This removes all hooks from your service, unloads the DLL and destroys the stub heap after the DLL has unloaded.

 

If you just call FreeLibrary(), any hooks installed in your service will remain in the service and may lead to a crash once the DLL is unloaded, and the stub heap workspace will not be freed, resulting in a memory leak.

 

warningnote If you use the load method above, you must also use the unload method prior to your application being closed down. It doesn't matter how the application is closed down but failure to do this will almost certainly result in a crash.

 

 

Setting a service notification callback

 

Once you have successfully loaded the Bug Validator DLL you can setup a service callback so that the service control manager can be kept updated during the process of starting the validator.

 

When a service is starting, Windows requires the service to inform the Service Control Manager (SCM) that is starting at least every ten seconds.

 

Failure to do so results in Windows concluding that the service has failed to start, and the service is terminated.

 

Instrumenting your service may well take more than 10 seconds, depending on the complexity and size of your service.

 

The solution is for Bug Validator to periodically call a user supplied callback from which you can regularly inform the SCM of the appropriate status.

 

extern "C" SVL_SERVICE_ERROR svlBVStub_SetServiceCallback(serviceCallback_FUNC callback, void *userParam);

 

userParam is a value you can supply which will then be passed to the callback every time the callback is called during instrumentation.

 

Here is an example callback which ignores the userParam.

 

   void serviceCallback(void   *userParam)
   {
       static DWORD dwCheckPoint = 1;
   
       ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
       ssStatus.dwServiceSpecificExitCode = 0;
 
       ssStatus.dwControlsAccepted = 0;
      
       ssStatus.dwCurrentState = dwCurrentState;
       ssStatus.dwWin32ExitCode = dwWin32ExitCode;
       ssStatus.dwWaitHint = dwWaitHint;
      
       ssStatus.dwCheckPoint = dwCheckPoint++;
      
       // Report the status of the service to the service control manager.
 
       return SetServiceStatus(sshStatusHandle, &ssStatus);
   }

 

 

Starting Bug Validator DLL in your service

 

Once you have successfully loaded the Bug Validator DLL you can start the Validator inspecting the service.

 

extern "C" SVL_SERVICE_ERROR svlBVStub_StartBugValidator();

 

 

Setting a filename for all logging data to be written to

 

To use any of the following logging functions you first need to set the name of the filename used for logging.

Setting this filename also sets the filename used by some of these API functions - you will find additional logging data from those functions that will help debug any issues with the service.

 

extern "C" void svlBVStub_setLogFileName(const wchar_t* fileName);
 

 

Deleting the logfile

 

This function deletes the log file.

 
extern "C" void svlBVStub_deleteLogFile();
 

 

Writing ANSI text to the logfile

 

Call this function to write a standard ANSI character string to the log file.

 
extern "C" void svlBVStub_writeToLogFileA(const char* text);
 

 

Write UNICODE text to the logfile

 

Call this function to write a unicode character string to the log file. The characters are cast to ANSI prior to writing. As such you can't write Korean to the log file. This is simply a convenience function to write wide characters as simply as ANSI characters.

 
extern "C" void svlBVStub_writeToLogFileW(const wchar_t* text);
 

 

Writing error code descriptions to the logfile

 

Call this function to write a human readable description of the SVL_SERVICE_ERROR error code to the log file.

 
extern "C" void svlBVStub_writeToLogFile(SVL_SERVICE_ERROR errCode);
 

 

Writing LastError code descriptions to the logfile

 

Call this function to write a human readable description of the Windows error code to the log file.

 
extern "C" void svlBVStub_writeToLogFileLastError(DWORD errCode);
 

 

Dumping the PATH environment to the logfile

 

Call this function to write the contents of the PATH environment variable to the log file. This can be useful if you want to know what the search path is when trying to debug why a DLL wasn't found during an attempt to load the Validator DLL.

 
extern "C" void svlBVStub_dumpPathToLogFile();

 

 

Bug Validator DLL behaviour

 

The DLL prepares itself in different ways and shuts itself down differently depending on whether:

 

The DLL is directly linked to the application for use with the API or injected with Bug Validator

 

The DLL expects to oversee and manage the application shutdown.

 

The DLL is loaded by using the function above

 

The DLL expects to be removed prior to application shutdown and the its behaviour is undefined once you enter the program shutdown sequence.

 

This difference in behaviour is intentional and is done to allow the use of the stub DLL in services.

 

 

Linker Problems

 

Some linkers cannot link the stub service library file.  If you have this problem see What do I do if I cannot use svlBVStubService.lib?