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.
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.
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 ... |
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().
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");
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.
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.
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.
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 ... |
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 ... |
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.
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 |
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.
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.
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.
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.
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.
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.
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.
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 # |
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().
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);}' |
Esta seção descreve ações que não são de registro de dados ou destrutivas.
As ações associadas ao rastreio especulativo são speculate (), commit() e discard(). Essas ações são tratadas no Capítulo 13Rastreio especulativo.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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).
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:
O mutex é declarado estaticamente
O mutex é criado com um cookie de bloqueio de interrupção de NULL
O mutex é criado com um cookie de bloqueio de interrupção que não corresponde a uma interrupção de alto nível
Consulte mutex_init(9F) para obter mais detalhes sobre mutexes. A maioria dos mutexes no kernel do Solaris são adaptáveis.
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.
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.
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).
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).
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.
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.
size_t strlen(string str)
strlen() retorna o tamanho da seqüência especificada em bytes, excluindo o byte nulo de terminação.