Artigo > Linux > System.map

O arquivo system.map

Parece haver escassez de informações sobre o arquivo System.map. Ele não é nada misterioso, e não é mesmo tão importante assim. Mas a falta de documentação torna-o sombrio. É como um lóbulo da orelha, que todos nós temos um, mas ninguém sabe por quê.

O que são símbolos?

No contexto da programação, um símbolo é o alicerce de um programa: é um nome de variável ou um nome de função.

O que é a tabela de símbolos do Kernel?

O Kernel não usa nomes para símbolos como BytesRead(). É muito mais fácil conhecer o nome da variável ou função, através do endereço como c0343f20. Os seres humanos, por outro lado, não apreciam endereços como c0343f20. Nós preferimos usar nomes de símbolos como BytesRead(). Normalmente, isso não representa um grande problema. O Kernel é principalmente escrito em C, assim o compilador/linkeditor nos permite usar nomes de símbolo quando estamos codificando e permite o Kernel usar endereços quando ele é executado. Todo mundo fica feliz.

Há situações, porém, que precisamos saber o endereço de um símbolo (ou o símbolo de um endereço). Isso é feito por uma tabela de símbolos, e é muito similar a como gdb pode dar-lhe o nome da função de um endereço (ou um endereço de um nome de função). A tabela de símbolos é uma listagem de todos os símbolos, juntamente com seu endereço. Aqui está um exemplo de uma tabela de símbolos:

c03441a0 B dmi_broken
c03441a4 B is_sony_vaio_laptop
c03441c0 b dmi_ident
c0344200 b pci_bios_present
c0344204 b pirq_table
c0344208 b pirq_router
c034420c b pirq_router_dev
c0344220 b ascii_buffer
c0344224 b ascii_buf_bytes

Você pode ver que a variável chamada dmi_broken está no endereço Kernel c03441a0.

O que é o arquivo system.map?

Há dois arquivos que são usados como tabelas de símbolos do Kernel:

1. /proc/kallsyms
2. System.map

Agora você já sabe o que é o arquivo System.map.

Cada vez que você compila um novo Kernel, é necessário mudar os endereços dos nomes de vários símbolos.

O /proc/kallsyms é um arquivo proc que é criado no momento em que o Kernel é carregado. Na verdade, não é realmente um arquivo em disco, é uma representação de dados do Kernel que é dado a ilusão de ser um arquivo de disco. Se você não acredita em mim, tenta encontrar o tamanho do arquivo /proc/kallsyms. Portanto, ele estará sempre pronto para o Kernel que está atualmente em execução.

No entanto, System.map é um arquivo no seu sistema de arquivos. Quando você compilar um novo Kernel, o System.map velho tem informações dos símbolos erradas. Um novo System.map é gerado para cada compilação do Kernel e que você precisa substituir a cópia de antiga por sua nova cópia.

O que é Oops?

Qual é o erro mais comum em seus programas caseiros? A falha de segmentação.

Qual é o erro mais comum no Kernel do Linux? A falha de segmentação. Salvo aqui, a noção de A falha de segmentação, ou segfault, é muito mais complicado e pode ser, como você pode imaginar, muito mais grave. Quando o Kernel referencia um ponteiro inválido, não é chamado um segfault – ele é chamado de “Oops”. Um Oops indica um erro de Kernel e deve sempre ser comunicado e corrigido.

Note-se que uma Oops não é a mesma coisa que um segfault. Seu programa (geralmente) não é possível se recuperar de um segfault. O Kernel não tem necessariamente de estar em um estado instável quando ocorre uma Oops. O Kernel do Linux é muito robusto, o Oops pode apenas matar o processo em curso e deixar o resto do Kernel em perfeito estado sólido.

Um Oops não é um Kernel Panic. Em pânico, o Kernel não pode continuar, o sistema é parado e deve ser reiniciado. Um Oops pode causar um panic se uma parte vital do sistema for destruída. Um Oops em um driver de dispositivo, por exemplo, quase nunca causa panic.

Quando ocorre uma Oops, o sistema irá imprimir as informações que são relevantes para a depuração do problema, como o conteúdo de todos os registos da CPU, e da localização das tabelas descritoras de página. Em particular, o conteúdo do EIP (instruction pointer) é impresso. Como esta:

EIP: 0010:[<00000000>]
Call Trace: []

O que um Oops tem a ver com System.map?

As informações prestadas em EIP e Call Trace não é muito informativa. Uma vez que um símbolo de Kernel não tem um endereço fixo até que o Kernel ser inicializado, c010b860 pode apontar para qualquer símbolo do Kernel. Desenvolvedores do Kernel não teriam a menor idéia por onde começar a olhar para o bug se você simplesmente informasse um endereço. Eles precisam de um nome de símbolo para começar a caçar o bug.

Para ajudar a entender a saída Oops crítica, um daemon chamado klogd, o Kernel logging daemon, é usado para executar a tradução de símbolo para endereços. Quando ocorre um Oops, o klogd intercepta o relatório Oops, traduz endereços em nomes de símbolo (por exemplo, traduzindo c010b860 em BytesRead()), e registra o evento com o logger do sistema, normalmente syslogd.

Para executar a resolução de endereços dos símbolos do Kernel, klogd usa o System.map.

Agora você sabe o que uma Oops tem a ver com System.map.

Fine Print: (como traduzir isso???)

Na verdade, existem dois tipos de resolução de endereço realizada por klogd.

* Tradução estática, que usa o arquivo System.map.
* Tradução dinâmica, que é usada com módulos carregáveis. Esta tradução não usa System.map e portanto, não é relevante para esta discussão, por isso vou descrever brevemente:

Tradução Dinâmica com Klogd

Suponha que você carregue um módulo do Kernel que gera uma Oops. Uma mensagem de Oops é gerado, e klogd intercepta-o. Verifica-se que o Oops ocorreu em d00cf810. Uma vez que este endereço pertence a um módulo carregado dinamicamente, não tem nenhuma entrada no arquivo System.map. klogd irá procurá-lo, não encontrará nada, e conclui que um módulo carregável deve ter gerado a Oops. Em seguida o klogd, consulta o Kernel para símbolos que foram exportados pelos módulos carregáveis. Mesmo que o autor do módulo não exportou seus símbolos, no mínimo, klogd vai saber o que gerou o módulo Oops, o que é melhor do que não saber nada sobre o Oops.

Onde deve ser localizado System.map?

System.map deve ser localizado em qualquer lugar onde o software que utiliza-o possa encontrá-lo. É a única resposta possível até que alguns standards board (ou alguém de autoridade clara) determine o local padrão para o System.map. Com isso em mente, olhe para alguns pacotes de software e descubra onde poderá encontrar o System.map.

klogd

Se não for dada ao klogd a localização do System.map como uma opção de linha de comando com a opção-k, ele utilizará a seguinte Mariz de possíveis locais (a partir da versão 1.4.1) para procurá-lo (ver arquivo de código fonte ksym.c:

static char *system_maps[] =
{
“/boot/System.map”,
“/System.map”,
#if defined(TEST)
“./System.map”,
#endif
(char *) 0
};

O klogd procura por dois arquivos nestes diretórios, o “System.map” e o “System.map-release” onde “release” é a versão do Kernel. Trata-se de uma pesquisa inteligente: se klogd encontra um System.map para uma versão do Kernel que é diferente do Kernel em execução no momento, ele vai continuar pesquisando.

Embora as páginas man klogd e comentários de código fonte aleguem que /usr/src/linux está no caminho de procura, não consigo encontrar qualquer referência a ele. Eu relatei este problema ao projeto Debian e ao Dr. G.W. Wettstein (o autor de ksym.c).

Device Drivers

System.map não é apenas útil para depurar Oops do Kernel. Alguns drivers necessitam do System.map para resolver símbolos, uma vez que estão ligados com cabeçalhos do Kernel em vez da glibc). Eles não funcionarão corretamente sem o System.map. Esta não é a mesma coisa que um módulo não carregar por causa de uma incompatibilidade de versão do Kernel, que tem a ver com a versão do Kernel, e não a tabela de símbolos do Kernel que muda entre as versões!

ps

PS usa uma matriz de busca diferentes (mais geral) do que klogd:

*sysmap_paths[] = {
“/boot/System.map-%s”,
“/boot/System.map”,
“/lib/modules/%s/System.map”,
“/usr/src/linux/System.map”,
“/System.map”,
NULL
};

Onde %s é substituído pela versão do Kernel atualmente em execução.

O que mais utiliza (ou não uso) o System.map

Em um momento (maio 2003), pensei que lsof e dosemu usavam o System.map, mas ao olhar o código fonte (Maio de 2007) eles não aparecem mais (ou talvez eu esteja enganado).

What Happens If I Don’t Have A Healthy System.map?

Suponha que você tenha vários Kernel na mesma máquina. Você precisa de um arquivo System.map separado para cada Kernel. Se você executar um Kernel com nenhum (ou um incorreto) System.map, você vai ver periodicamente avisos irritantes como:

System.map does not match actual Kernel

Toda vez que você usa ps. Além disso, sua saída klogd ksymOops pode não ser confiável em caso de um Kernel Oops.

Fontes:

http://dirac.org/linux/system.map/
http://wrbraga.blogspot.com

Outros materiais:

http://www.frankmarcel.com/seo/oracao-google-nosso
http://www.faqs.org/docs/Linux-HOWTO/Kernel-HOWTO.html
http://en.wikipedia.org/wiki/System.map
http://www.cathedrallabs.org/~landgraf/apresentacoes/2007-09-29-Desenvolvimento_do_Kernel_Linux.pdf

Deixe uma resposta

This site uses Akismet to reduce spam. Learn how your comment data is processed.