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

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

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

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

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

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

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

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

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

плагины: 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” для либы надо указывать как-то более человечно, для бинаря наверно попроще будет.

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

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

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

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

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

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

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

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!

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

Причем, что самое интересное, если создать такой же проект, но типа 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 настроить.

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

Так… Как настраивать 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?

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

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

[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 из исходников.

Собрал 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. Пока мне с дебагами разбираться надоело.

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


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

Тут я в очередной раз баловался - и свалил 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. (апдейт: собрал, не помогло)