Guia de rastreamento dinâmico Solaris

Capítulo 10 Ações e sub-rotinas

Você pode usar chamadas de função de D como trace() e printf() para chamar dois tipos diferentes de serviços fornecidos pelo DTrace: ações que rastreiam dados ou modificam o estado externo do DTrace e sub-rotinas que afetam somente o estado interno do DTrace. Este capítulo define as ações e as sub-rotinas e descreve sua sintaxe e semântica.

Ações

As ações permitem que os programas do DTrace interajam com o sistema fora do DTrace. As ações mais comuns registram dados em um buffer do DTrace. Outras ações estão disponíveis, como a interrupção do processo atual, a elevação de um sinal específico no processo atual ou a interrupção do rastreio totalmente. Algumas dessas ações são destrutivas, pois alteram o sistema, ainda que numa maneira bem definida. Essas ações só podem ser usadas se as ações destrutivas tiverem sido explicitamente ativadas. Por padrão, as ações de registro de dados registram os dados no buffer principal. Para obter mais detalhes sobre o buffer principal e as diretivas de buffer, consulte o Capítulo 11Buffers e armazenamento em buffer.

Ação padrão

Uma cláusula pode conter qualquer número de ações e manipulações de variáveis. Se uma cláusula for deixada em branco, a ação padrão será realizada. A ação padrão é rastrear o identificador do teste ativado (EPID ) para o buffer principal. O EPID identifica uma ativação particular de um teste específico com ações e predicados particulares. Do EPID, os consumidores do DTrace podem determinar o teste que induziu a ação. Na verdade, sempre que quaisquer dados forem rastreados, eles devem ser acompanhados pelo EPID para que façam sentido para o consumidor. Por isso, a ação padrão é rastrear o EPID e nada mais.

O uso da ação padrão permite o uso simples de dtrace(1M). Por exemplo, o seguinte comando ativa todos os testes no módulo de agendamento de uso compartilhado TS com a ação padrão:


# dtrace -m TS

O comando anterior pode produzir um resultado similar ao do seguinte exemplo:


# dtrace -m TS
dtrace: description 'TS' matched 80 probes
CPU     ID                    FUNCTION:NAME
  0  12077                 ts_trapret:entry 
  0  12078                ts_trapret:return 
  0  12069                   ts_sleep:entry 
  0  12070                  ts_sleep:return 
  0  12033                  ts_setrun:entry 
  0  12034                 ts_setrun:return 
  0  12081                  ts_wakeup:entry 
  0  12082                 ts_wakeup:return 
  0  12069                   ts_sleep:entry 
  0  12070                  ts_sleep:return 
  0  12033                  ts_setrun:entry 
  0  12034                 ts_setrun:return 
  0  12069                   ts_sleep:entry 
  0  12070                  ts_sleep:return 
  0  12033                  ts_setrun:entry 
  0  12034                 ts_setrun:return 
  0  12069                   ts_sleep:entry 
  0  12070                  ts_sleep:return 
  0  12023                  ts_update:entry 
  0  12079             ts_update_list:entry 
  0  12080            ts_update_list:return 
  0  12079             ts_update_list:entry 
...

Ações de registro de dados

As ações de registro de dados abrangem as principais ações do DTrace. Cada uma dessas ações registra dados no buffer principal por padrão, mas cada ação também pode ser usada para registrar dados em buffers especulativos. Consulte o Capítulo 11Buffers e armazenamento em buffer para obter mais detalhes sobre o buffer principal. Consulte o Capítulo 13Rastreio especulativo para obter mais detalhes sobre buffers especulativos. As descrições desta seção referem-se somente ao buffer direcionado, indicando que os dados são registrados no buffer principal ou em um buffer especulativo se a ação for após uma speculate().

trace()

void trace(expression)

A ação mais básica é a trace(), que possui uma expressão de D como seu argumento e rastreia o resultado para o buffer direcionado. As seguintes instruções são exemplos de ações trace():

trace(execname);
trace(curlwpsinfo->pr_pri);
trace(timestamp / 1000);
trace(`lbolt);
trace("somehow managed to get here");

tracemem()

void tracemem(address, size_t nbytes)

A ação tracemem() possui uma expressão de D como seu primeiro argumento, endereço e uma constante como seu segundo argumento, nbytes. tracemem () copia a memória do endereço especificado por addr para o buffer direcionado, de acordo com o tamanho especificado por nbytes.

printf()

void printf(string format, ...) 

Como trace(), a ação printf() rastreia expressões de D. Entretanto, printf() permite uma formatação de estilo printf(3C) elaborada. Como printf(3C), os parâmetros consistem em uma seqüência de formato seguida por um número variável de argumentos. Por padrão, os argumentos são rastreados para o buffer direcionado. Os argumentos depois são formatados como resultado por dtrace(1M), de acordo com a seqüência de formato especificada. Por exemplo, os dois primeiros exemplos de trace() de trace() poderiam ser combinados em uma única printf():

printf("execname is %s; priority is %d", execname, curlwpsinfo->pr_pri);

Para obter mais informações sobre printf(), consulte o Capítulo 12Formatação de saída.

printa()

void printa(aggregation)
void printa(string format, aggregation)

A ação printa() permite que você exiba e formate agregações. Consulte o Capítulo 9Agregações para obter mais detalhes sobre agregações. Se um formato não for fornecido, printa() rastreará somente uma diretiva para o consumidor do DTrace de que a agregação especificada deve ser processada e exibida usando-se o formato padrão. Se um formato for fornecido, a agregação será formatada como especificado. Consulte o Capítulo 12Formatação de saída para obter uma descrição mais detalhada da seqüência de formato printa().

printa() rastreia somente uma diretiva de que a agregação deve ser processada pelo consumidor do DTrace. Ela não processa a agregação no kernel. Portanto, o tempo entre o rastreio da diretiva de printa() e o processamento real da diretiva depende dos fatores que afetam o processamento do buffer. Esses fatores incluem a taxa de agregação, a política de armazenamento em buffer e, se essa política for de alternância, a taxa na qual os buffers são alternados. Consulte o Capítulo 9Agregações e o Capítulo 11Buffers e armazenamento em buffer para obter descrições detalhadas sobre esses fatores.

stack()

void stack(int nframes)
void stack(void)

A ação stack() registra um rastreio de pilha do kernel para o buffer direcionado. A pilha do kernel terá nframes de profundidade. Se nframes não for fornecida, o número de quadros de pilha registrado será o número especificado pela opção stackframes . Por exemplo:


# dtrace -n uiomove:entry'{stack()}'
  CPU     ID                    FUNCTION:NAME
    0   9153                    uiomove:entry 
                genunix`fop_write+0x1b
                namefs`nm_write+0x1d
                genunix`fop_write+0x1b
                genunix`write+0x1f7

    0   9153                    uiomove:entry 
                genunix`fop_read+0x1b
                genunix`read+0x1d4

    0   9153                    uiomove:entry 
                genunix`strread+0x394
                specfs`spec_read+0x65
                genunix`fop_read+0x1b
                genunix`read+0x1d4
   ...

A ação stack() é um pouco diferente de outras ações pois ela também pode ser usada como a chave para uma agregação:


# dtrace -n kmem_alloc:entry'{@[stack()] = count()}'
dtrace: description 'kmem_alloc:entry' matched 1 probe
^C

                rpcmod`endpnt_get+0x47c
                rpcmod`clnt_clts_kcallit_addr+0x26f
                rpcmod`clnt_clts_kcallit+0x22
                nfs`rfscall+0x350
                nfs`rfs2call+0x60
                nfs`nfs_getattr_otw+0x9e
                nfs`nfsgetattr+0x26
                nfs`nfs_getattr+0xb8
                genunix`fop_getattr+0x18
                genunix`cstat64+0x30
                genunix`cstatat64+0x4a
                genunix`lstat64+0x1c
                  1

                genunix`vfs_rlock_wait+0xc
                genunix`lookuppnvp+0x19d
                genunix`lookuppnat+0xe7
                genunix`lookupnameat+0x87
                genunix`lookupname+0x19
                genunix`chdir+0x18
                  1

                rpcmod`endpnt_get+0x6b1
                rpcmod`clnt_clts_kcallit_addr+0x26f
                rpcmod`clnt_clts_kcallit+0x22
                nfs`rfscall+0x350
                nfs`rfs2call+0x60
                nfs`nfs_getattr_otw+0x9e
                nfs`nfsgetattr+0x26
                nfs`nfs_getattr+0xb8
                genunix`fop_getattr+0x18
                genunix`cstat64+0x30
                genunix`cstatat64+0x4a
                genunix`lstat64+0x1c
                  1
    ...

ustack()

void ustack(int nframes, int strsize)
void ustack(int nframes)
void ustack(void)

A ação ustack() registra um rastreio de pilha do usuário para o buffer direcionado. A pilha do usuário terá nframes de profundidade. Se nframes não for fornecida, o número de quadros de pilha registrado será o número especificado pela opção ustackframes. Embora ustack() possa determinar o endereço dos quadros de chamada quando o teste for acionado, os quadros de pilha não serão traduzidos em símbolos até que a ação ustack() seja processada no nível do usuário pelo consumidor do DTrace. Se strsize for especificado e diferente de zero, ustack() irá alocar a quantidade especificada de espaço de seqüência e usá-la para realizar a tradução de endereço para símbolo diretamente do kernel. Essa tradução de símbolo direta do usuário atualmente está disponível apenas para máquinas virtuais com Java, versão 1.5 e posterior. A tradução de endereço em símbolo de Java anota as pilhas de usuário que contêm quadros de Java com o nome de método e classe de Java. Se tais quadros não puderem ser traduzidos, os quadros aparecerão somente como endereços hexadecimais.

O exemplo a seguir rastreia uma pilha sem espaço de seqüência e, portanto, nenhuma tradução de endereço em símbolo de Java:


# dtrace -n syscall::write:entry'/pid == $target/{ustack(50, 0); 
    exit(0)}' -c "java -version"
dtrace: description 'syscall::write:entry' matched 1 probe
java version "1.5.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b58)
Java HotSpot(TM) Client VM (build 1.5.0-beta3-b58, mixed mode)
dtrace: pid 5312 has exited
CPU     ID                    FUNCTION:NAME
  0     35                      write:entry 
              libc.so.1`_write+0x15
              libjvm.so`__1cDhpiFwrite6FipkvI_I_+0xa8
              libjvm.so`JVM_Write+0x2f
              d0c5c946
              libjava.so`Java_java_io_FileOutputStream_writeBytes+0x2c
              cb007fcd
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb002a7b
              cb000152
              libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_
                          pnMmethodHandle_pnRJavaCallArguments_
                          pnGThread__v_+0x187
              libjvm.so`__1cCosUos_exception_wrapper6FpFpnJJavaValue_
                          pnMmethodHandle_pnRJavaCallArguments_
                          pnGThread__v2468_v_+0x14
              libjvm.so`__1cJJavaCallsEcall6FpnJJavaValue_nMmethodHandle_
                          pnRJavaCallArguments_pnGThread __v_+0x28
              libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_
                          pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_
                          ArgumentPusher_pnGThread__v_+0x180
              libjvm.so`jni_CallStaticVoidMethod+0x10f
              java`main+0x53d

Observe que os quadros de pilhas de C e C++ da máquina virtual com Java são apresentados simbolicamente usando-se nomes de símbolos “corrompidos” de C++ e os quadros de pilhas de Java são apresentados somente como endereços hexadecimais. O exemplo a seguir mostra uma chamada para ustack() com um espaço de seqüência diferente de zero:


# dtrace -n syscall::write:entry'/pid == $target/{ustack(50, 500); exit(0)}'
      -c "java -version"
dtrace: description 'syscall::write:entry' matched 1 probe
java version "1.5.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b58)
Java HotSpot(TM) Client VM (build 1.5.0-beta3-b58, mixed mode)
dtrace: pid 5308 has exited
CPU     ID                    FUNCTION:NAME
  0     35                      write:entry 
              libc.so.1`_write+0x15
              libjvm.so`__1cDhpiFwrite6FipkvI_I_+0xa8
              libjvm.so`JVM_Write+0x2f
              d0c5c946
              libjava.so`Java_java_io_FileOutputStream_writeBytes+0x2c
              java/io/FileOutputStream.writeBytes
              java/io/FileOutputStream.write
              java/io/BufferedOutputStream.flushBuffer
              java/io/BufferedOutputStream.flush
              java/io/PrintStream.write
              sun/nio/cs/StreamEncoder$CharsetSE.writeBytes
              sun/nio/cs/StreamEncoder$CharsetSE.implFlushBuffer
              sun/nio/cs/StreamEncoder.flushBuffer
              java/io/OutputStreamWriter.flushBuffer
              java/io/PrintStream.write
              java/io/PrintStream.print
              java/io/PrintStream.println
              sun/misc/Version.print
              sun/misc/Version.print
              StubRoutines (1)
              libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_
                          pnMmethodHandle_pnRJavaCallArguments_pnGThread
                          __v_+0x187
              libjvm.so`__1cCosUos_exception_wrapper6FpFpnJJavaValue_
                          pnMmethodHandle_pnRJavaCallArguments_pnGThread
                          __v2468_v_+0x14
              libjvm.so`__1cJJavaCallsEcall6FpnJJavaValue_nMmethodHandle
                          _pnRJavaCallArguments_pnGThread__v_+0x28
              libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_pnI
                          _jobject_nLJNICallType_pnK_jmethodID_pnSJNI
                          _ArgumentPusher_pnGThread__v_+0x180
              libjvm.so`jni_CallStaticVoidMethod+0x10f
              java`main+0x53d
              8051b9a

O exemplo de resultado acima demonstra informações simbólicas de quadro de pilhas de Java. Ainda existem alguns quadros hexadecimais nesse resultado porque algumas funções são estáticas e não possuem entradas na tabela de símbolos do aplicativo. A translação não é possível nesses quadros.

A translação de símbolo de ustack() para quadros que não sejam de Java ocorre depois que os dados da pilha são registrados. Por isso, o processo do usuário correspondente deve ser encerrado antes que a tradução de símbolo possa ser realizada, tornando a tradução do quadro de pilhas impossível. Se o processo do usuário for encerrado antes que a translação de símbolo seja realizada, o dtrace emitirá uma mensagem de aviso, seguida pelos quadros de pilhas hexadecimais, conforme mostrado no exemplo a seguir:


  dtrace: failed to grab process 100941: no such process
                c7b834d4
                c7bca85d
                c7bca1a4
                c7bd4374
                c7bc2628
                8047efc

As técnicas para atenuar esse problema são descritas no Capítulo 33Rastreio de processo do usuário.

Finalmente, como os comandos post mortem do depurador do DTrace não podem realizar a tradução do quadro, o uso de ustack() com uma política de buffer ring sempre resulta em dados ustack() não processados.

O programa em D a seguir mostra um exemplo de ustack() que deixa strsize sem especificação:

syscall::brk:entry
/execname == $$1/
{
	@[ustack(40)] = count();
}

Para executar este exemplo para o navegador da Web Netscape, .netscape.bin em instalações padrão do Solaris, use o seguinte comando:


# dtrace -s brk.d .netscape.bin
dtrace: description 'syscall::brk:entry' matched 1 probe
^C
                libc.so.1`_brk_unlocked+0xc
                88143f6
                88146cd
                .netscape.bin`unlocked_malloc+0x3e
                .netscape.bin`unlocked_calloc+0x22
                .netscape.bin`calloc+0x26
                .netscape.bin`_IMGCB_NewPixmap+0x149
                .netscape.bin`il_size+0x2f7
                .netscape.bin`il_jpeg_write+0xde
                8440c19
                .netscape.bin`il_first_write+0x16b
                8394670
                83928e5
                .netscape.bin`NET_ProcessHTTP+0xa6
                .netscape.bin`NET_ProcessNet+0x49a
                827b323
                libXt.so.4`XtAppProcessEvent+0x38f
                .netscape.bin`fe_EventLoop+0x190
                .netscape.bin`main+0x1875
                   1

                libc.so.1`_brk_unlocked+0xc
                libc.so.1`sbrk+0x29
                88143df
                88146cd
                .netscape.bin`unlocked_malloc+0x3e
                .netscape.bin`unlocked_calloc+0x22
                .netscape.bin`calloc+0x26
                .netscape.bin`_IMGCB_NewPixmap+0x149
                .netscape.bin`il_size+0x2f7
                .netscape.bin`il_jpeg_write+0xde
                8440c19
                .netscape.bin`il_first_write+0x16b
                8394670
                83928e5
                .netscape.bin`NET_ProcessHTTP+0xa6
                .netscape.bin`NET_ProcessNet+0x49a
                827b323
                libXt.so.4`XtAppProcessEvent+0x38f
                .netscape.bin`fe_EventLoop+0x190
                .netscape.bin`main+0x1875
                  1
    ...

jstack()

void jstack(int nframes, int strsize)
void jstack(int nframes)
void jstack(void)

jstack() é um alias para ustack() que usa a opção jstackframes para o número de quadros de pilha e para o tamanho de espaço de seqüência cujo valor é especificado pela opção jstackstrsize. O padrão de jstacksize é um valor diferente de zero. Isso significa que o uso de jstack() resultará em um pilha com tradução de quadro de Java no local.

Ações destrutivas

Algumas ações do DTrace são destrutivas pois alteram o estado do sistema de uma forma bem definida. As ações destrutivas não podem ser usadas a menos que tenham sido explicitamente ativadas. Ao usar o dtrace(1M), você pode ativar ações destrutivas usando a opção -w. Se for feita uma tentativa de ativar ações destrutivas no dtrace(1M) sem ativá-las explicitamente, haverá uma falha no dtrace com uma mensagem similar ao seguinte exemplo:


dtrace: failed to enable 'syscall': destructive actions not allowed

Ações destrutivas de processo

Algumas ações são destrutivas somente para um processo em particular. Essas ações estão disponíveis para usuários com os privilégios dtrace_proc ou dtrace_user. Consulte o Capítulo 35Segurança para obter detalhes sobre privilégios de segurança do DTrace.

stop()

void stop(void)

A ação stop () força o processo que aciona o teste ativado para parar quando ele deixar o kernel da próxima vez, como se fosse interrompido por uma ação proc(4). O utilitário prun(1) pode ser usado para resumir um processo que foi interrompido pela ação stop(). A ação stop() pode ser usada para interromper um processo em qualquer ponto do teste de DTrace. Essa ação pode ser usada para capturar um programa em um estado particular que seria difícil de alcançar com um simples ponto de interrupção e depois anexar um depurador tradicional como o mdb(1) ao processo. Você também pode usar o utilitário gcore(1) para salvar o estado de um processo interrompido em um arquivo de núcleo para análise posterior.

raise()

void raise(int signal)

A ação raise () envia o sinal especificado para o processo em execução no momento. Essa ação é similar ao uso do comando kill(1) para enviar um sinal a um processo. A ação raise() pode ser usada para enviar um sinal em um ponto preciso na execução de um processo.

copyout()

void copyout(void *buf, uintptr_t addr, size_t nbytes)

A ação copyout() copia nbytes do buffer especificado por buf para o endereço especificado por addr no espaço de endereço do processo associado ao segmento atual. Se o endereço do espaço do usuário não corresponder a uma página válida, com falhas, no espaço de endereço atual, um erro será gerado.

copyoutstr()

void copyoutstr(string str, uintptr_t addr, size_t maxlen)

A ação copyoutstr() copia a seqüência especificada por str para o endereço especificado por addr no espaço de endereço do processo associado ao segmento atual. Se o endereço do espaço do usuário não corresponder a uma página válida, com falhas, no espaço de endereço atual, um erro será gerado. O tamanho da seqüência é limitado ao valor definido pela opção strsize. Consulte o Capítulo 16Opções e ajustáveis para obter detalhes.

system()

void system(string program, ...) 

A ação system () faz com que o programa especificado por programa seja executado como se fosse fornecido ao shell como entrada. A seqüência de programa pode conter qualquer uma das conversões de formato de printf()/ printa. () Os argumentos que correspondam às conversões de formato devem ser especificados. Consulte o Capítulo 12Formatação de saída para obter detalhes sobre as conversões de formato válidas.

O exemplo a seguir executa o comando date(1) uma vez por segundo:


# dtrace -wqn tick-1sec'{system("date")}'
 Tue Jul 20 11:56:26 CDT 2004
 Tue Jul 20 11:56:27 CDT 2004
 Tue Jul 20 11:56:28 CDT 2004
 Tue Jul 20 11:56:29 CDT 2004
 Tue Jul 20 11:56:30 CDT 2004

O exemplo a seguir mostra um uso mais elaborado da ação, usando conversões de printf() na seqüência de programa junto com ferramentas de filtragem tradicionais como pipes:

#pragma D option destructive
#pragma D option quiet

proc:::signal-send
/args[2] == SIGINT/
{
	printf("SIGINT sent to %s by ", args[1]->pr_fname);
	system("getent passwd %d | cut -d: -f5", uid);
}

Executar o script acima resultará numa saída semelhante ao exemplo seguinte:


# ./whosend.d
SIGINT sent to MozillaFirebird- by Bryan Cantrill
SIGINT sent to run-mozilla.sh by Bryan Cantrill
^C
SIGINT sent to dtrace by Bryan Cantrill

A execução do comando especificado não ocorre no contexto do teste acionado – ela ocorre quando o buffer que contém os detalhes da ação system() é processado no nível do usuário. Como e quando esse processamento ocorre depende da política de buffer, descrita no Capítulo 11Buffers e armazenamento em buffer. Com a política de buffer padrão, a taxa de processamento do buffer é especificada pela opção switchrate . Você poderá ver o atraso inerente em system() se ajustar explicitamente switchrate com um valor mais alto que o padrão de um segundo, conforme mostrado no exemplo a seguir:

#pragma D option quiet
#pragma D option destructive
#pragma D option switchrate=5sec

tick-1sec
/n++ < 5/
{
	printf("walltime  : %Y\n", walltimestamp);
	printf("date      : ");
	system("date");
	printf("\n");
}

tick-1sec
/n == 5/
{
	exit(0);
}

Executar o script acima resultará numa saída semelhante ao exemplo seguinte:


# dtrace -s ./time.d
 walltime  : 2004 Jul 20 13:26:30
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:31
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:32
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:33
date      : Tue Jul 20 13:26:35 CDT 2004

walltime  : 2004 Jul 20 13:26:34
date      : Tue Jul 20 13:26:35 CDT 2004

Observe que os valores de walltime diferem, mas os valores de date são idênticos. Esse resultado reflete o fato de que a execução do comando date(1) ocorreu somente quando o buffer foi processado, não quando a ação system() foi registrada.

Ações destrutivas do kernel

Algumas ações são destrutivas para todo o sistema. Essas ações obviamente devem ser usadas com muito cuidado, pois elas irão afetar todos os processos no sistema e qualquer outro sistema que dependa implicita ou explicitamente dos serviços de rede do sistema afetado.

breakpoint()

void breakpoint(void)

A ação breakpoint() induz a um ponto de interrupção do kernel, fazendo com que o sistema pare e transfira o controle para o depurador do kernel. O depurador do kernel emitirá uma seqüência indicando o teste do DTrace que acionou a ação. Por exemplo, se a seguinte ação fosse realizada:


# dtrace -w -n clock:entry'{breakpoint()}'
dtrace: allowing destructive actions
dtrace: description 'clock:entry' matched 1 probe

No Solaris em execução no SPARC, a seguinte mensagem poderia aparecer no console:


dtrace: breakpoint action at probe fbt:genunix:clock:entry (ecb 30002765700)
Type  'go' to resume
ok

No Solaris em execução no x86, a seguinte mensagem poderia aparecer no console:


dtrace: breakpoint action at probe fbt:genunix:clock:entry (ecb d2b97060)
stopped at      int20+0xb:      ret
kmdb[0]:

O endereço após a descrição do teste é o endereço do bloco de controle de ativação (ECB) no DTrace. Você pode usar esse endereço para determinar mais detalhes sobre a ativação do teste que induziu a ação de ponto de interrupção.

Um erro na ação breakpoint() pode fazer com que ela seja chamada mais vezes do que o pretendido. Esse comportamento pode, por sua vez, impedir até mesmo que você encerre o consumidor do DTrace que está acionando as ações de ponto de interrupção. Nessa situação, defina a variável de inteiro do kernel dtrace_destructive_disallow como 1. Essa configuração irá impedir todas as ações destrutivas na máquina. Aplique essa configuração somente nessa situação em particular.

O método exato para a definição de dtrace_destructive_disallow dependerá do depurador do kernel que você está usando. Se estiver usando o PROM de OpenBoot em um sistema SPARC, use w!:


ok 1 dtrace_destructive_disallow w!
ok

Confirme que a variável foi definida usando-se w?:


ok dtrace_destructive_disallow w?
1
ok

Continue digitando go:


ok go

Se estiver usando kmdb(1) em sistemas x86 ou SPARC, use o modificador de gravação de 4 bytes (W) com o dcmd de formatação /:


kmdb[0]: dtrace_destructive_disallow/W 1
dtrace_destructive_disallow:    0x0             =       0x1
kmdb[0]:

Continue usando :c:


kadb[0]: :c

Para reativar ações destrutivas após prosseguir, você precisará redefinir explicitamente dtrace_destructive_disallow de volta para 0 usando mdb(1):


# echo "dtrace_destructive_disallow/W 0" | mdb -kw
dtrace_destructive_disallow:    0x1             =       0x0
#

panic()

void panic(void)

A ação panic () causa um aviso grave no kernel quando acionada. Essa ação deve ser usada para forçar um despejo de memória do sistema quando for necessário. Você pode usar essa ação junto com o buffer de anel e a análise post mortem para compreender um problema. Para obter mais informações, consulte o Capítulo 11Buffers e armazenamento em buffer e o Capítulo 37Rastreio post-mortem respectivamente. Quando a ação panic é usada, uma mensagem é exibida indicando o teste que causou o aviso grave. Por exemplo:


  panic[cpu0]/thread=30001830b80: dtrace: panic action at probe
  syscall::mmap:entry (ecb 300000acfc8)

  000002a10050b840 dtrace:dtrace_probe+518 (fffe, 0, 1830f88, 1830f88,
    30002fb8040, 300000acfc8)
    %l0-3: 0000000000000000 00000300030e4d80 0000030003418000 00000300018c0800
    %l4-7: 000002a10050b980 0000000000000500 0000000000000000 0000000000000502
  000002a10050ba30 genunix:dtrace_systrace_syscall32+44 (0, 2000, 5,
    80000002, 3, 1898400)
    %l0-3: 00000300030de730 0000000002200008 00000000000000e0 000000000184d928
    %l4-7: 00000300030de000 0000000000000730 0000000000000073 0000000000000010

  syncing file systems... 2 done
  dumping to /dev/dsk/c0t0d0s1, offset 214827008, content: kernel
  100% done: 11837 pages dumped, compression ratio 4.66, dump
  succeeded
  rebooting...

syslogd(1M) também emitirá uma mensagem na reinicialização:


  Jun 10 16:56:31 machine1 savecore: [ID 570001 auth.error] reboot after panic:
  dtrace: panic action at probe syscall::mmap:entry (ecb 300000acfc8)

O buffer de mensagem do despejo de memória também contém o teste e o ECB responsável pela ação panic().

chill()

void chill(int nanoseconds)

A ação chill () faz com que o DTrace gire para o número especificado de nanossegundos. chill() é principalmente útil para explorar problemas que possam estar relacionados ao tempo. Por exemplo, você pode usar essa ação para abrir janelas de condição de corrida ou para colocar ou tirar eventos periódicos de fase entre si. Como as interrupções são desativadas durante o contexto de teste do DTrace, qualquer uso de chill() irá induzir à latência de interrupção, latência de agendamento e latência de distribuição. Portanto, chill() pode causar efeitos sistêmicos não esperados e não deve ser usada indiscriminadamente. Como a atividade do sistema depende de uma manipulação periódica de interrupção, o DTrace irá se recusar a executar a ação chill() por mais de 500 milissegundos de cada intervalo de um segundo em uma determinada CPU. Se o intervalo máximo de chill() for excedido, o DTrace irá relatar um erro de operação ilegal, conforme mostrado no seguinte exemplo:


# dtrace -w -n syscall::open:entry'{chill(500000001)}'
dtrace: allowing destructive actions
dtrace: description 'syscall::open:entry' matched 1 probe
dtrace: 57 errors
CPU     ID                    FUNCTION:NAME
dtrace: error on enabled probe ID 1 (ID 14: syscall::open:entry): \
  illegal operation in action #1

Esse limite é aplicado mesmo que o tempo seja distribuído entre várias chamadas para chill() ou vários consumidores de DTrace de um único teste. Por exemplo, o mesmo erro seria gerado pelo seguinte comando:


# dtrace -w -n syscall::open:entry'{chill(250000000); chill(250000001);}'

Ações especiais

Esta seção descreve ações que não são de registro de dados ou destrutivas.

Ações especulativas

As ações associadas ao rastreio especulativo são speculate (), commit() e discard(). Essas ações são tratadas no Capítulo 13Rastreio especulativo.

exit()

void exit(int status)

A ação exit() é usada para interromper o rastreio imediatamente e para informar ao consumidor do DTrace que ele deve interromper o rastreio, realizar o processamento final e chamar exit(3C) com o status especificado. Como exit() retorna um status para o nível do usuário, ela é uma ação de registro de dados. Entretanto, ao contrário de outras ações de armazenamento de dados, exit() não pode ser rastreada especulativamente. exit() fará com que o consumidor do DTrace seja encerrado independentemente da política do buffer. Como exit() é uma ação de registro de dados, ela pode ser cancelada.

Quando exit() é chamada, somente as ações do DTrace já em andamento em outras CPUs serão concluídas. Nenhuma ação nova ocorrerá em qualquer CPU. A única exceção a essa regra é o processamento do teste END, que será chamado depois que o consumidor do DTrace tiver processado a ação exit() e indicado que o rastreio deve ser encerrado.

Sub-rotinas

As sub-rotinas são diferentes das ações porque elas geralmente afetam apenas o estado interno do DTrace. Portanto, não há sub-rotinas destrutivas e as sub-rotinas nunca rastreiam dados para buffers. Muitas sub-rotinas possuem análogos nas interfaces da Seção 9F ou da Seção 3C. Consulte Intro(9F) e Intro(3) para obter mais informações sobre as sub-rotinas correspondentes.

alloca()

void *alloca(size_t size)

alloca() aloca tamanho bytes fora do espaço temporário e retorna um ponteiro para a memória alocada. É garantido que o ponteiro retornado tenha um alinhamento de 8 bytes. O espaço temporário só é válido enquanto durar uma cláusula. A memória alocada com alloca() será desalocada quando a cláusula for concluída. Se não houver espaço temporário suficiente disponível, não será alocada a memória e um erro será gerado.

basename()

string basename(char *str)

basename() é um análogo de D para basename(1). Esta sub-rotina cria uma seqüência que consiste em uma cópia da seqüência especificada, mas sem um prefixo que termine em /. A seqüência retornada é alocada fora da memória temporária e, portanto, é válida somente enquanto durar a cláusula. Se não houver espaço temporário suficiente disponível, basename não será executada e um erro será gerado.

bcopy()

void bcopy(void *src, void *dest, size_t size)

bcopy() copia tamanho bytes da memória apontada por src para a memória apontada por dest. Toda a memória de origem deve estar fora da memória temporária e toda a memória de destino deve estar dentro dela. Se essas condições não forem atendidas, a cópia não será realizada e um erro é gerado.

cleanpath()

string cleanpath(char *str)

cleanpath() cria uma seqüência que consiste em uma cópia do caminho indicado por str, mas com alguns elementos redundantes eliminados. Em particular, os elementos “/./” no caminho são removidos e os elementos “/../” são recolhidos. Os elementos /../ são recolhidos no caminho sem levar em consideração os links simbólicos. Portanto, é possível que cleanpath() obtenha um caminho válido e retorne um mais curto, inválido.

Por exemplo, se str fosse “ /foo/../bar” e /foo fosse um link simbólico para /net/foo/export, cleanpath() retornaria a seqüência “/bar” embora bar só possa estar em /net/foo e não em /. Essa limitação deve-se ao fato de que cleanpath() é chamada no contexto de um teste acionado, onde a resolução completa de link simbólico ou nomes arbitrários não são possíveis. A seqüência retornada é alocada fora da memória temporária e, portanto, é válida somente enquanto durar a cláusula. Se não houver espaço temporário suficiente disponível, cleanpath não será executada e um erro será gerado.

copyin()

void *copyin(uintptr_t addr, size_t size)

copyin()copia o tamanho especificado em bytes do endereço de usuário especificado em um buffer temporário do DTrace e retorna o endereço desse buffer. O endereço do usuário é interpretado como um endereço no espaço do processo associado ao segmento atual. É garantido que o ponteiro de buffer resultante tenha um alinhamento de 8 bytes. O endereço em questão deve corresponder a uma página com falhas no processo atual. Se o endereço não corresponder a uma página com falhas, ou não houver espaço temporário suficiente disponível, NULL será retornado e um erro será gerado. Consulte o Capítulo 33Rastreio de processo do usuário para saber as técnicas para reduzir a probabilidade de erros de copyin.

copyinstr()

string copyinstr(uintptr_t addr)

copyinstr() copia uma seqüência de C terminada com caractere nulo do endereço de usuário especificado para um buffer temporário do DTrace e retorna o endereço desse buffer. O endereço do usuário é interpretado como um endereço no espaço do processo associado ao segmento atual. O tamanho da seqüência é limitado pelo valor definido pela opção strsize. Consulte o Capítulo 16Opções e ajustáveis para obter detalhes. Assim como com copyin, o endereço especificado deve corresponder a uma página com falhas no processo atual. Se o endereço não corresponder a uma página com falhas, ou não houver espaço temporário suficiente disponível, NULL será retornado e um erro será gerado. Consulte o Capítulo 33Rastreio de processo do usuário para saber as técnicas para reduzir a probabilidade de erros de copyinstr.

copyinto()

void copyinto(uintptr_t addr, size_t size, void *dest)

copyinto()copia o tamanho especificado em bytes do endereço de usuário especificado para o buffer temporário do DTrace especificado por dest. O endereço do usuário é interpretado como um endereço no espaço do processo associado ao segmento atual. O endereço em questão deve corresponder a uma página com falhas no processo atual. Se o endereço não corresponder a uma página com falhas, ou se uma das memórias de destino estiver fora do espaço temporário, não ocorrerá uma cópia e um erro será gerado. Consulte o Capítulo 33Rastreio de processo do usuário para saber as técnicas para reduzir a probabilidade de erros de copyinto.

dirname()

string dirname(char *str)

dirname() é um análogo de D para dirname(1). Essa sub-rotina cria uma seqüência que consiste em todos os níveis, exceto o último, do nome de caminho especificado por str. A seqüência retornada é alocada fora da memória temporária e, portanto, é válida somente enquanto durar a cláusula. Se não houver espaço temporário suficiente disponível, dirname não será executada e um erro é gerado.

msgdsize()

size_t msgdsize(mblk_t *mp)

msgdsize() retorna o número de bytes na mensagem de dados apontada por mp. Consulte msgdsize(9F) para obter detalhes. msgdsize() inclui somente blocos de dados do tipo M_DATA na contagem.

msgsize()

size_t msgsize(mblk_t *mp)

msgsize() retorna o número de bytes na mensagem apontada por mp. Ao contrário de msgdsize (), que retorna somente o número de bytes dos dados, msgsize() retorna o número total de bytes na mensagem.

mutex_owned()

int mutex_owned(kmutex_t *mutex)

mutex_owned() é uma implementação de mutex_owned(9F). mutex_owned() retorna um valor diferente de zero se o segmento de chamada possuir atualmente o mutex do kernel especificado ou zero se o mutex adaptável especificado não possuir proprietário no momento.

mutex_owner()

kthread_t *mutex_owner(kmutex_t *mutex)

mutex_owner() retorna o ponteiro do segmento do proprietário atual do mutex do kernel adaptável especificado. mutex_owner() retorna NULL se o mutex adaptável especificado não possuir proprietário no momento ou se o mutex especificado for um mutex de rotação. Consulte mutex_owned(9F).

mutex_type_adaptive()

int mutex_type_adaptive(kmutex_t *mutex)

mutex_type_adaptive() retorna um valor diferente de zero se o mutex do kernel especificado for do tipo MUTEX_ADAPTIVE , ou zero se não for. Os mutexes são adaptáveis se atenderem a uma ou mais das seguintes condições:

Consulte mutex_init(9F) para obter mais detalhes sobre mutexes. A maioria dos mutexes no kernel do Solaris são adaptáveis.

progenyof()

int progenyof(pid_t pid)

progenyof() retorna um valor diferente de zero se o processo de chamada (o processo associado ao segmento que está acionando atualmente o teste correspondido) estiver entre a origem do ID especificado do processo.

rand()

int rand(void)

rand() retorna um inteiro pseudo-aleatório. O número retornado é um número pseudo-aleatório fraco e não deve ser usado para qualquer aplicação criptográfica.

rw_iswriter()

int rw_iswriter(krwlock_t *rwlock)

rw_iswriter() retorna um valor diferente de zero se o bloqueio de leitor-autor especificado for mantido ou desejado por um autor. Se o bloqueio for mantido somente por leitores e nenhum autor estiver bloqueado ou se o bloqueio não for mantido, rw_iswriter() retornará zero. Consulte rw_init(9F).

rw_write_held()

int rw_write_held(krwlock_t *rwlock)

rw_write_held() retorna um valor diferente de zero se o bloqueio de leitor-autor especificado estiver sendo mantido atualmente por um autor. Se o bloqueio for mantido somente por leitores ou não for mantido, rw_write_held () retornará zero. Consulte rw_init(9F).

speculation()

int speculation(void)

speculation() reserva um buffer de rastreio especulativo para uso com speculate() e retorna um identificador para esse buffer. Consulte o Capítulo 13Rastreio especulativo para obter detalhes.

strjoin()

string strjoin(char *str1, char *str2)

strjoin() cria uma seqüência que consiste em str1 concatenado com str2. A seqüência retornada é alocada fora da memória temporária e, portanto, é válida somente enquanto durar a cláusula. Se não houver espaço temporário suficiente disponível, strjoin não será executada e um erro será gerado.

strlen()

size_t strlen(string str)

strlen() retorna o tamanho da seqüência especificada em bytes, excluindo o byte nulo de terminação.