В чем дебажить программы на rust?

Тех.вопросы
ide
Mar 29, 2017
C

Погуглил я эту тему. Первое, что советуют - RustDT, и первое, что понимаешь, когда пытаешься работать с этой программой - авторы сами ни разу с ней не работали. Компилить проект можно только 1 раз, все последующие - компилятор ожидает разлочивания директории build. Дебаггер глючит, у меня напечатал переменную дважды, причем, например, если это ссылка на i32, то он печатает ее адрес, а не значение по этому адресу. И как заставить его напечатать значение - я так и не нашел. При этом само окошко переменных глчит - выделения мигают, работать невозможно.

idea. Где-то в issue я находил, что в идею добавили возможность дебага, но пока это существует только в исходниках, и из за бага в cargo позволяет дебажить только программы, запущенные без аргументов. Ставить еще не пробовал.

rust-gdb. ваппер вокруг gdb. Наверное, для 70ых это было бы круто, но для 2017 так дэбажить - это же извращение.

O

Говорят что в VS Code удобная отладка.

Лично я как раз извращенец - пишу в vim и отлаживаюсь логами или принтами. С типажом Debug это, как по мне, довольно удобно.

C

Это ж вижуал студия. Она только для винды.

O
Replying to #3

Нет, VS Code это другой проект, он вообще открытый: https://github.com/Microsoft/vscode

W

С небольшими приседаниями мне удалось натравить дебаггер на либку:

плагины: rust, lldb

конфиг дебага:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "lldb",
      "request": "launch",
      "name": "Debug",
      "program": "${workspaceRoot}/target/debug/deps/l6-a2c0a35411de4316",
      "args": [],
      "cwd": "${workspaceRoot}",
      "sourceLanguages": ["rust"]
    }
  ]
}

“program” для либы надо указывать как-то более человечно, для бинаря наверно попроще будет.

C
Replying to #5

Да, я вчера тоже посмотрел VS code - юзабельно, хотя кодкомплитер “из коробки” совершенно идиотский, бессмысленный и беспощадный.

W
Replying to #6

Это который? Там два плагина. И в любом случае дополнение поставляется рейсером - оно одинаковое во всех IDE.

C
Replying to #7

не знаю, я поставил плагин Rust, он предложил доставить всякого барахла, долго качал, компилил, ставил. Никаких новых расширений он не доставил, но после этого стал работать автокомплит, но стал предлагать слишком много: нажимаешь stru - он тебе предлагает не только структуру - но и скобочки и поля в ней, при этом, если ты согласен - то добавлял в конец набраного тобой. Сегодня баг куда-то делся, он заменят твое, но все равно предлагает чрезмерно много. Еще и #[derive(Debug)] над структурой ставит. Но это уже неособо критичный момент

W
Replying to #8

А мне наоборот понравилось… Сервис…

D

Насколько я знаю, оно ещё и работает не во всех “редакциях” IDE и в IDEA как раз не работает. Нужен, например, Clion. Хотя сам тоже не пробовал (пользуюсь IDEA, обхожусь логами).

C
Replying to #10

да, там говорили, что запустили дебаг в CLion

C
Replying to #5

А у вас оно во время дебага не ругается, что не может открыть системные файлы?
Например:

Unable to open ‘pthread_cond_timedwait.S’: File not found (/build/buildd/eglibc-2.19/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S)

это при попытке сдеать step over такой строке:
let s = CString::new(“abcd”).unwrap();

При этом, gdb тоже ругается, но не так как lldb:
Unable to open ‘c_str.rs’: File not found (/checkout/src/libstd/ffi/c_str.rs).

Но мне ненадо туда заходить! Я хочу сделать шаг step over а не step into!

W
Replying to #12

Да, ругается. Вообще у меня выкачаны исходники стдлиба (для рейсера или чего-то такого) и надо source mapping настроить. Но мне пока недостаточно не лень.

C

Причем, что самое интересное, если создать такой же проект, но типа bin, то дебаг работает относительно нормально. При том, что все равно ссылки на эти файлы бинарнике есть. Если выполнить objdump -g target/debug/binproba >file.txt, то помимо остального, там можно найти такое:

 The Directory Table (offset 0x1b):
  1     /hitachi-hdd/sources_razn/rust/src-my/3/binproba/src
  2     /checkout/src/libcore
  3     /checkout/src/libcore/fmt
  4     /checkout/src/libcore/fmt/rt
  5     /checkout/src/libcollections
  6     /checkout/src/libstd/ffi
  7     /checkout/src/libstd
  8     /checkout/src/liballoc
  9     /checkout/src/libcore/str
  10    /checkout/src/libcore/slice
  11    /checkout/src/libcore/iter

 The File Name Table (offset 0x151):
  Entry Dir     Time    Size    Name
  1     1       0       0       main.rs
  2     0       0       0       <println macros>
  3     0       0       0       <panic macros>
  4     0       0       0       <assert_eq macros>
  5     2       0       0       lib.rs
  6     2       0       0       result.rs
  7     3       0       0       mod.rs
  8     4       0       0       v1.rs
  9     2       0       0       option.rs
  10    5       0       0       slice.rs
  11    5       0       0       lib.rs
  12    6       0       0       c_str.rs
  13    7       0       0       lib.rs
  14    6       0       0       mod.rs
  15    8       0       0       raw_vec.rs
  16    8       0       0       lib.rs
  17    2       0       0       ptr.rs
  18    2       0       0       nonzero.rs
  19    2       0       0       marker.rs
  20    9       0       0       mod.rs
  21    5       0       0       vec.rs
  22    2       0       0       cmp.rs
  23    10      0       0       mod.rs
  24    2       0       0       mem.rs
  25    2       0       0       macros.rs
  26    2       0       0       convert.rs
  27    11      0       0       traits.rs
  28    11      0       0       mod.rs
  29    8       0       0       heap.rs
  30    2       0       0       ops.rs

С одной стороны, это проясняет, почему дебажные файлы такие больше - в них есть дебажная инфа либ, и возможно, это хорошо. С другой, возникает вопрос - а что за каталог /checkout, у меня такого нет, есть только тот, что под номером 1. И почему когда дебажишь bin - то все работает, а когда пытаешься дебажить тест - не работает. И вот эта ошибка, которая выскакивает - она в VS code валит всю сессию. Хотя, консольный rust-gdb работает в обеих случаях.

Вообще у меня выкачаны исходники стдлиба (для рейсера или чего-то такого) и надо source mapping настроить.

сейчас пойду смотреть, как его настраивать…

C

Так… Как настраивать source mapping я так и не разобрался. Но зато вот что я выяснил. Оно по-разному работает с разными версиями gdb и lldb.

У убунте 14.04 доступна одна какая-то версия gdb, консольно оно работает, с VS code - может выбрыкиваться и ругаться на исходники, если отлаживаешь либы.

lldb доступно в версиях: 3.{3,4,5,6,8}
И так же к vs code есть 2 плагина: LLDB debugger и Native debug.

Native debug работает с lldb-mi. В чем отличие mi от не mi - вроде бы mi это более продвинутая версия, но как мы видим, это ей не помогло.
LLDB debugger - по всей видимости, работает с lldb

Оба дебаггера про rust вроде как ничего не знают.

3.8 - не показывает переменные в консольнм режиме и не работает нормально ни с одним из плагинов.
3.6 - вроде работает консольно, вроде работает с плагином LLDB debugger (правда, не умеет разворачивать Result - но это понт) но не работает с Native debug.
3.5 - судя по rust-lldb не рабочий по жизни.
Остальные не пробовал.

Впринципе - неплохой повод разобраться с консольным дебажиньем кода. Всегда было интересно что люди в этом находят - но никогда руки до этого не доходили.

как узнать, какой версии llvm в rustc?

O

можно еще https://github.com/cs01/gdbgui пощупать

C
Replying to #16

задумка, возможно, хорошая, но при попытке загрузить исходник выдало такое:

[2017-03-31 23:59:42,309] ERROR in app: Exception on /read_file [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib/python2.7/dist-packages/gdbgui/backend.py", line 311, in read_file
    highlight = json.loads(request.args.get('highlight', 'true'))
  File "/usr/lib/python2.7/json/__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.7/json/decoder.py", line 366, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python2.7/json/decoder.py", line 384, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

При попытке нажать “run” тоже ругается: INTERNAL SERVER ERROR (500 error)
И ddd я тоже пробовал - вообще глючная штука.

В настоящий момент я выяснил в чем был баг. Плагин LLDB debugger рассчитан на lldb-4.0
ее в репозиториях убунты 14.04 нету - но есть репозитории самого lldb. Оттуда можно ее поставить - и тогда vscode работает. И кроме того, там консольный дебаггер, скажем так - можно привыкнуть. Единственное, что плохо - в консольном дебаггере стрелки вверх-вниз не листают по истории, а выводят в консоль “^[[A” и “^[[B”. Так же, не работают стрелки вправо-влево. Я даже на лор спросил об этом, может там можно что-то доставить, и оно заработает.

Да что ж оно все такое глючное и нестабильное? Или это я разбалован java где всегда все работало идеально.

в репах llvm есть 3.9, и ее можно поставить. В ней стрелки в консоли работают - но все переменные показывает равными None, и с vs code оно не работает.

Наиболее рабочей выглядит 3.6 - она в репах убунты, но руст собран с llvm-4.0.

Возможно, завтра попытаюсь собрать lldb-4.0 из исходников.

C

Собрал lldb с исходников. Вобщем да, работает, и баги с клавиатурой ушли. Видимо, тот что в идет в репах плохо собран: размер либы liblldb.so около 25мб, а мой собранный - 75мб. Что свидетельствует о неполном функционале lldb с репозитория.

В lldb в четвертом даже есть гуи - включается командой gui. Но к сожалению - недоделано. Согластно http://stackoverflow.com/questions/27957058/documentation-for-lldbs-gui оно появилось совсем недавно, и еще недоделано.

Итог такой.

Дебажить можно:

  1. В связке vscode + LLDB debugger+ lldb-4.0

  2. Или, rust-gdb (ставится когда ставишь раст) - при этом мне пришлось пересобрать gdb - и тогда даже как-то работает TUI хотя в реальной работе не пробовал. Но вообще, можно и без пересборки.

  3. Или rust-lldb. gui там недоделан, так что про него можно забыть, а вот консольный дебаг работает относительно хорошо, хотя свои приколы тоже имеются. При этом, lldb тоже желательно пересобрать, т.к. в репах оно собрано не всегда хорошо.

Может по свободе попробую еще собрать пятый lldb. Пока мне с дебагами разбираться надоело.

S

Официально в идее дебага еще нет.


CLion может что-то прожевать, выдаваемое Rust, но все это неприглядно выглядит.

C

Тут я в очередной раз баловался - и свалил lldb. Интерсно, у вас падает (падать по идее должно и в графическом дебаггере, если у него “снизу” lldb)
Значит, есть следующий код:

use std::collections::HashMap;

#[derive(Debug)]
enum En<'a> {
    None,
    Bar(&'a Bar<'a>),
}

#[derive(Debug)]
struct Bar<'a> {
    next: En<'a>,
}


fn main() {
    let mut all_objects = HashMap::new();
    let bar: Bar = Bar {
        next: En::None,
    };
    all_objects.insert(1, bar);
    let b1 = all_objects.get(&1).unwrap();
    println!("b1={:?}", b1); //это строка номер 22
    println!("end");
}

Пытаюсь дебажить через lldb (собраный, или посталенный из пакетов - не важно), ставлю брикпоинт на 22 строку, выполняю, пытаюсь распечатать b1. Получается так:

(lldb) target create "target/debug/test"
Current executable set to 'target/debug/test' (x86_64).
(lldb) b 22
Breakpoint 1: 2 locations.
(lldb) r
Process 16849 launched: '/home/chabapok/RustProjects/2/test1/target/debug/test' (x86_64)
Process 16849 stopped
* thread #1, name = 'test', stop reason = breakpoint 1.1
    frame #0: 0x000055555556501f test`test::main at main.rs:22
   19  	    };
   20  	    all_objects.insert(1, bar);
   21  	    let b1 = all_objects.get(&1).unwrap();
-> 22  	    println!("b1={:?}", b1);
   23  	    println!("end");
   24  	}
(lldb) p b1
error: test DWARF DIE at 0x0000007c (class En) has a member variable 0x00000082 (RUST$ENCODED$ENUM$0$None) whose type is a forward declaration, not a complete definition.
Please file a bug against the compiler and include the preprocessed output for /home/chabapok/RustProjects/2/test1/./src/main.rs
Stack dump:
0.	HandleCommand(command = "p b1")
1.	<eof> parser at end of file
2.	Parse:41:1: Generating code for declaration '$__lldb_expr'
Segmentation fault

пробовал снять коредамп и посмотреть стек. Там 14964 стакфреймов, оно там входит в рекурсию.
Фиг его знает, чей это баг - то ли lldb, то ли clang, то ли плохой формат dwarf. В рекурсию оно входит в файле, который относится к clang (tools/clang/AST/RecordLayoutBuilder.cpp)

Фиг его знает, че дальше делать. Я не настолько еще гуру, чтобы знать это… Куда правильно слать багрепотры в такой ситуации? Или что еще можно попробовать? Я слышал, что rust работает на патченой llvm, но вроде бы(если я правильно нашел репозиторий) последние коммиты в патченную llvm были несколько лет назад.

llvm собирал с исходников, с ветки stable, lldb и clang - с ветки master. Наверное сейчас надо попробовать llvm взять тоже из master. Хотя, вряд ли это поможет, ведь падает в коде clang. (апдейт: собрал, не помогло)