Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

Трассировка вызовов, завершений и сбросов функий

From Wiki
Jump to: navigation, search
Article Metadata

Статья
Перевод:
truf
Последнее редактирование: hamishwillee (09 Dec 2011)

Зачастую, в процессе отладки полезно знать какие именно функции вызывались, и в каком порядке. Добавление RDebug::Print в начало и конец всех интересующих вас функций может стать весьма утомительным и занять много времени. Помимо этого, использование в функции оператора return может помешать срабатыванию RDebug::Print в конце тела функции. <p>Автоматические переменные (объекты, создаваемые в стеке) уничтожаются, как только выходят из области видимости. Размещение объекта для логгирования в стеке - самый легкий способ определить вызов и завершение работы функции, несмотря на использование в ее теле операторов return.

Функция также может завершить выполнение в результате сброса, и отследить это бывает очень полезным. Начиная с S60 3-й редакции, сбросы реализуются в виде исключений. C++ предоставляет функцию std::uncaught_exception() для того, чтобы определить, произошло ли необработанное исключение.

Значение, возвращаемое функцией, также может быть определено, так как в 32-битной системе оно всегда будет 32-битным значением. Это требует использования вставок на ассемблерного кода, что в свою очередь не обеспечивает портируемость между различными типами сборки проекта (WINSCV, GCCE и т.п.), поэтому для каждой сборки этот код будет разным.

Contents

Простой пример

Это простой трассировщик, выводящий вызовы, завершения и сбросы функций через RDebug или в файл. Он также может определять значение, возвращаемое функцией. Он реализован в виде обычного T класса, используемого в качестве автоматической переменной функции. В его конструкторе вызывается метод, согнализирующий о начале работы функции, а в деструкторе - сигнализирующий о ее завершении (возможно, в результате сброса). Он может определить значение, возвращаемое функцией, если проект был собран для WINSCW.

Файл: tracer.h

#ifndef TTRACER_H
#define TTRACER_H
 
#include <e32base.h>
 
// Определение метода трассировки
// 0 = Логгирование отключено
// 1 = Вывод данных через RDebug
// 2 = Вывод в файл (используется RFileLogger)
#define TRACER_LOG_METHOD 2
 
// ============================================================================
 
// Логгирование отключено - определяем пустые макросы
#if TRACER_LOG_METHOD == 0
 
#define TRACER(func)
#define TRACER_RET(func,format)
 
#else // Логгирование включено
 
// Макрос для печати вызова, завершения и сброса функции.
// Пример: TRACER("CMyClass::MyFunction");
#define TRACER(func) TTracer function_tracer( _S(func), _S("") );
 
// Макрос для печати вызова, завершения и сброса функции, дополнительно
// выводящий возвращенное функцией значение.
// Пример: TRACER_RET("CMyclass::MyFunction", "%d");
#define TRACER_RET(func,format) TTracer func_tracer( _S(func), _S(format) );
 
#if TRACER_LOG_METHOD == 1 // Вывод через RDebug
 
#include <e32debug.h>
#define TRACER_PRINT(a) RDebug::Print(a,&iFunc);
#define TRACER_PRINT_RET(a,b) RDebug::Print(a,&iFunc,b);
 
#elif TRACER_LOG_METHOD == 2 // Вывод в файл
 
#include <flogger.h>
_LIT( KLogDir, "tracer" ); // Папка для сохранения лога: C:\logs\tracer
_LIT( KLogFile, "tracer.txt" ); // Файл для хранения лога: c:\logs\tracer\tracer.txt
#define TRACER_PRINT(a) RFileLogger::WriteFormat(KLogDir, \
KLogFile,EFileLoggingModeAppend,a,&iFunc);

#define TRACER_PRINT_RET(a,b) RFileLogger::WriteFormat(KLogDir, \
KLogFile,EFileLoggingModeAppend,a,&iFunc,b);

 
#endif
 
_LIT( KLogEnter, "%S: ENTER" );
_LIT( KLogExit, "%S: EXIT" );
_LIT( KLogLeave, "%S: LEAVE!" );
_LIT( KLogExitRet, "%S: EXIT, Returning " );
 
/**
* Простой трейсер для логирования вызова, завершения и сброса функции
*/

class TTracer
{
public:
 
/**
* inline конструктор для вывода сообщения о вызове функции
*/

TTracer( const TText* aFunc, const TText* aRetFormat )
: iFunc( aFunc )
, iRetFormat( aRetFormat )
{
TRACER_PRINT( KLogEnter );
}
 
/**
* inline деструктор для вывода сообщения о выходе из функции
* (обычном, или в результате сброса)
*/

~TTracer()
{
if ( std::uncaught_exception() ) // Произошел сброс (исключение)
{
// Функция завершила работу в результате сброса
TRACER_PRINT( KLogLeave );
}
else
{
// Функция завершила работу штатно
if ( iRetFormat.Length() == 0 )
{
TRACER_PRINT( KLogExit );
}
else
{
// Выводим возвращенное функцией значение
#ifdef __WINS__
TInt32 retVal = 0;
 
// Небольшая ассемблерная вставка. Ее нужно изменить
// при использовании для других целевых сборок.
_asm( mov retVal, ebx );
 
TBuf<100> format( KLogExitRet );
format.Append( iRetFormat );
TRACER_PRINT_RET( format, retVal );
#else
TRACER_PRINT( KLogExit );
#endif
}
}
}
 
private:
 
/**
* Дескриптор-указатель, содержащий имя функции.
*/

TPtrC iFunc;
 
/**
* Строка, используемая для форматирования возвращаемого функцией значения
*/

TPtrC iRetFormat;
 
};
 
#endif // TRACER_LOG_METHOD == 0
 
#endif // TTRACER_H

Использование

#include "tracer.h"
 
// Вывод вызова, завершения или сброса функции
void CSomeClass::SomeFunctionL()
{
TRACER( "CSomeClass::SomeFunctionL" );
...
}
// Выводится:
// CSomeClass::SomeFunctionL: ENTER
// CSomeClass::SomeFunctionL: EXIT
// или
// CSomeClass::SomeFunctionL: LEAVE
 
// Вывод вызова, завершения или сброса функции,
// а также возвращенного ей значения (числа)
TInt CSomeClass::ReturnSomeInt()
{
TRACER_RET( "CSomeClass::ReturnSomeInt", "%d" );
...
return 42;
}
// Выводится:
// CSomeClass::ReturnSomeInt: ENTER
// CSomeClass::ReturnSomeInt: EXIT, Returning 42
// или
// CSomeClass::ReturnSomeInt: LEAVE
 
// Вывод вызова, завершения или сброса функции,
// а также возвращенного ей значения (дескриптора)
HBufC* CSomeClass::ReturnSomeDescL()
{
TRACER_RET( "CSomeClass::ReturnSomeDescL", "%S" );
return _L("Test data").AllocL();
}
// Выводится:
// CSomeClass::ReturnSomeDescL: ENTER
// CSomeClass::ReturnSomeDescL: EXIT, Returning Test data
// или
// CSomeClass::ReturnSomeDescL: LEAVE

Вспомогательный скрипт

Это простой скрипт, написанный на perl, который считывает содержимое CPP файла и добавляет макрос TRACER в начало каждой функции. Он сохраняет оригинальный файл в качестве резервной копии под другим именем. Скрипт не добавляет макрос TRACER_RET в функции, возвращающие значения - это необходимо сделать самостоятельно.

add_traces.pl

# add_traces.pl (C) Marko Kivijärvi 2006
# Dummy checks
die "Specify an input file!\n" if $ARGV[0] eq "";
die "File not found!\n" unless -e $ARGV[0];
die "Incorrect file extension for a C/C++ file!\n"
if ( $ARGV[0] !~ /(.*)\.(c|cpp)$/ );
 
# Constants
my $INC_TRACER_H = "#include \"tracer.h\"\n";
my $TRACER = "TRACER";
 
# Parse output filename from the input filename
my $file = $ARGV[0];
my $origFile = $1."-orig.".$2;
system( "copy $file, $origFile" );
 
# Reset the input record separator (newline) so the entire file is read at once
undef $/;
 
# Read the input file
$_ = <>; # All there
 
# Adds a tracer macro after each function definition
s/
(\b\w*?\b[&*]?)? # Possible function return type
\s+ # One or more empty spaces
(\b\w+?\b) # Class name
\s*? # Possible empty space
:: # ::
\s*? # Possible empty space
(~?\b\w+?\b) # Function name
\s*? # Possible empty space
\( # Opening brace
([^)]*?) # Possible function parameters
\) # Closing brace
\s*? # Possible empty space
(const)? # Possible 'const'
[^{;\/]*? # Possible empty space or constructor
# initializer list
\{ # Opening curly brace
/
Parse($&,$1,$2,$3,$4,$5) # Print the match and add the macro
/gxe; # g = repeat, x = split regex to multiple lines, e = evaluate substitution
 
open OUT, ">$file" or die "Cannot open file $file $!\n";
print OUT $INC_TRACER_H;
print OUT;
close OUT;
 
exit 0;
 
sub Parse {
my $match = shift;
my $ret = shift;
my $class = shift;
my $func = shift;
my $param = shift;
my $const = shift;
 
foreach ( $ret, $class, $func, $param ) {
s/^\s+|\s+$//g;
s/\n//g;
}
 
my $debug = $match."\n ";
$debug .= $TRACER."(";
$debug .= $ret." " if defined $ret;
$debug .= $class."::".$func."(";
$debug .= $param if $param ne "";
$debug .= ")";
$debug .= " ".$const if defined $const;
$debug .= ")";
 
return $debug;
}

Дополнительную информацию об обработке сбросов можно найти здесь: Использование ловушки(TRAP).

This page was last modified on 9 December 2011, at 00:52.
35 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×