Как да намеря къде е дефиниран символ сред статични библиотеки

Да предположим, че работите с кодова база, включваща няколко инструмента и библиотеки, и искате да пренесете (или възкресите) някакъв компонент в рамките на такава кодова база, но всяка следа за това къде се намират символите в различните библиотеки е или изгубена, или ще отнеме много време, за да разберете, като погледнете самия код (да, подобрената документация може да избегне подобни проблеми, но е доста взискателна). Кой е най-бързият начин да откриете в коя библиотека можете да намерите символи, използвани в кода?


person a1an    schedule 11.11.2013    source източник


Отговори (3)


Ако приемем кутия с linux, инструментът nm, изброяващ имена в библиотечни файлове, идва на помощ.

Може да се използва за извършване на обширно търсене, както следва: първо можете да намерите всички налични библиотеки (ако приемем, че проектът е бил компилиран успешно без компонента, който добавяте) с намиране, след което това намиране може да бъде затворено в цикъл, където можете обадете се на nm на всички открити библиотеки; изходът, който след това grep за отхвърляне на "U" препратки (недефинирани символи, известен още като къде другаде се използва символът). На един bash ред, който дава:

for lib in $(find base_path -name \*.a) ; do echo $lib ; nm $lib | grep my_symbol | grep -v " U "   ; done

където:

  • base_path е коренът на вашата кодова база
  • my_symbol е символът, който търсите

Ехото генерира списък с всички намерени библиотеки, което не е толкова чисто, тъй като извежда имена на библиотеки, които не съдържат символа, но това беше най-бързият начин, който намерих за директна препратка към библиотеката, така че когато видите:

base_path/component/libA.a
0000000000000080 D my_symbol

Намерихте обичайния си заподозрян.

person a1an    schedule 11.11.2013
comment
опцията -A на nm ще отпечата името на файла. Премахване на необходимостта от ехо $lib във вашия пример. - person Tyson Hilmer; 12.11.2019

С помощта на nm е възможно да се изброят символите, дефинирани в двоичен файл, а ключът --defined-only игнорира недефинирани препратки.

Вариант 1: find

В една команда:

find $path -name \*.a -exec bash -c "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}" \;

където $path е коренът на файловото дърво, съдържащо двоичните файлове, а $symbol е името на символа, който търсите.

Вариант 2: find + GNU parallel

Изпълнението на nm на всички файлове може да отнеме време, така че може да е полезно да обработите резултатите от find паралелно (с помощта на GNU parallel):

find $path -name \*.a | parallel "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}"

Вариант 3: fd

И накрая, моят любим. Използването на инструмента fd, който има по-опростен синтаксис от find, обикновено е по-бърз и обработва резултатите паралелно по подразбиране:

fd '.*\.a$' -x bash -c "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}"

Прост бенчмарк

Търся символа gz_write в /usr/lib на моя лаптоп:

  • find отнема около 23 секунди
  • find | parallel отнема около 10 секунди
  • fd отнема около 8 секунди
person m-pilia    schedule 25.05.2019

Използването на превключвателя --defined-only на nm е полезно тук, тъй като ще премахне недефинираните препратки. По-долу е даден csh скрипт, който може да бъде полезен за други.

#!/bin/csh
#
#recurse from current dir and output name of any .a files
#that contain the desired symbol.
echo "Search for: $1"
foreach i (`find . -name '*.a'`)
    nm --defined-only $i | grep $1
    if ($status == 0) then
        echo $i
    endif
end
person eric gilbertson    schedule 24.05.2016