Encontrando o caminho absoluto das bibliotecas compartilhadas usadas por um executável

5

Considerando lshw como um programa de exemplo, eis o que ldd fornece:

$ ldd /usr/sbin/lshw    

linux-vdso.so.1 =>  (0x00007fff8bdaf000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x000000360e400000)
libsqlite3.so.0 => /lib64/libsqlite3.so.0 (0x0000003631600000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x000000360ec00000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000360d800000)
libc.so.6 => /lib64/libc.so.6 (0x000000360c000000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x000000360cc00000)
libdl.so.2 => /lib64/libdl.so.2 (0x000000360c800000)
libm.so.6 => /lib64/libm.so.6 (0x000000360c400000)
/lib64/ld-linux-x86-64.so.2 (0x000000360bc00000)

Se eu quiser encontrar os locais absolutos das bibliotecas compartilhadas (e quiser excluir o linux-vdso.so.1 por razões óbvias), como faço para isso? Usando O awk com expressões regulares parece frágil aqui. ldd tem um sinalizador detalhado (-v) que imprime os caminhos completos das bibliotecas compartilhadas, mas não é muito amigável para a leitura de máquinas.

Existe outra maneira de fazer isso? Se alguém souber de uma chamada de sistema para fazer isso, também estou bem com isso.

PS: Para um pouco de contexto, eu quero rodar este programa em chroot jail, então eu preciso ter certeza de que as bibliotecas compartilhadas estão todas disponíveis. Compilá-lo estaticamente funciona sem todo esse drama, mas esse é um caminho que eu estou tentando evitar.

Atualização:

Acho que may encontrei algo que pode ser mais adequado ao ler o livro de Michael Kerrisk, "The Linux Programming Interface". Se eu executar um programa como $ LD_DEBUG=libs lshw , ele gerará várias informações úteis. Por exemplo:

$ LD_DEBUG=libs lshw 
     32058:     find library=libresolv.so.2 [0]; searching
     32058:      search cache=/etc/ld.so.cache
     32058:       trying file=/lib64/libresolv.so.2
     32058:
     32058:     find library=libstdc++.so.6 [0]; searching
     32058:      search cache=/etc/ld.so.cache
     32058:       trying file=/lib64/libstdc++.so.6
     32058:
     32058:     find library=libgcc_s.so.1 [0]; searching
     32058:      search cache=/etc/ld.so.cache
     32058:       trying file=/lib64/libgcc_s.so.1
     32058:
     32058:     find library=libc.so.6 [0]; searching
     32058:      search cache=/etc/ld.so.cache
     32058:       trying file=/lib64/libc.so.6
     32058:
     32058:     find library=libm.so.6 [0]; searching
     32058:      search cache=/etc/ld.so.cache
     32058:       trying file=/lib64/libm.so.6
     32058:
     32058:
     32058:     prelink checking: ok
     32058:
     32058:     calling init: /lib64/ld-linux-x86-64.so.2
     32058:
     32058:
     32058:     calling init: /lib64/libc.so.6
     32058:
     32058:
     32058:     calling init: /lib64/libm.so.6
     32058:
     32058:
     32058:     calling init: /lib64/libgcc_s.so.1
     32058:
     32058:
     32058:     calling init: /lib64/libstdc++.so.6
     32058:
     32058:
     32058:     calling init: /lib64/libresolv.so.2


     <more output>

Eu acho que, se eu procurar as linhas 'chamando init', terei os caminhos da biblioteca compartilhada que ela está inicializando antes de iniciar a execução do programa.

    
por Amit 02.08.2013 / 04:38

3 respostas

6

Você pode tentar o awk sem usar o regex:

ldd /bin/ls | awk 'NF == 4 {print $3}; NF == 2 {print $1}'

Saída:

/lib/x86_64-linux-gnu/libselinux.so.1
/lib/x86_64-linux-gnu/librt.so.1
/lib/x86_64-linux-gnu/libacl.so.1
/lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libdl.so.2
/lib64/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/libpthread.so.0
/lib/x86_64-linux-gnu/libattr.so.1
    
por 02.08.2013 / 05:43
2

Eu sei que você disse que não quer regexes, mas o '= >' na linha facilita a análise. Mesmo o modo verboso usa isso, então você pode até mesmo passar a saída detalhada através da regex (com alguns ajustes). Eu usei apenas um comando como uma lista de variáveis de loop (para i in ...) para configurar um ambiente chroot.

Então, darei duas maneiras de fazer isso, primeiro com o sed:

    ldd /path/to/binary | egrep -v 'linux-vdso|ld-linux-x86-64' | sed 's/.*\=> \(.*\) (.*//'

Ou, você pode tentar analisá-lo em espaços em branco com algo como:

    ldd /path/to/binary | egrep -v 'linux-vdso|ld-linux-x86-64' | cut -f 3 -d ' '

Ambos me dão o seguinte:

    ldd /bin/ls | egrep -v 'linux-vdso|ld-linux-x86-64' | cut -f 3 -d ' '
    /lib/libselinux.so.1
    /lib/librt.so.1
    /lib/libacl.so.1
    /lib/libc.so.6
    /lib/libdl.so.2
    /lib/libpthread.so.0 
    /lib/libattr.so.1
    
por 02.08.2013 / 05:12
1

Com o GNU grep:

ldd /usr/sbin/lshw | grep -Po '/.*(?= \(0x)'

Se você puder garantir que esses caminhos não contenham caracteres de espaço, você poderá simplificá-lo para:

ldd /usr/sbin/lshw | grep -o '/[^ ]*'

com sed :

ldd /usr/sbin/lshw | sed -n 's,[^/]*\(/.*\) (0x.*,,p'

A ideia é obter tudo, desde o primeiro / até o último (0x

    
por 02.08.2013 / 12:40