Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0005314OCamlOCaml generalpublic2011-07-10 13:012013-08-31 12:48
Reporterygrek 
Assigned Toshinwell 
PrioritynormalSeverityfeatureReproducibilityalways
StatusclosedResolutionfixed 
PlatformOSOS Version
Product Version3.12.0 
Target VersionFixed in Version3.13.0+dev 
Summary0005314: add CFI directives for reliable stack unwinding
DescriptionCurrently in many cases stack of ocaml programs cannot be unwinded because there is no usual frame pointer and generic debuggers and profilers (e.g. gdb,oprofile) are often confused. But using DWARF2 CFI directives it is possible to add static information for frame address calculation. These directives are understood by GNU assembler and stored in .debug_frame or .eh_frame sections, which can be later used by debugging tools. Patch attached for x86 and amd64 code emitters. Here are some examples :

$ cat test.ml

let really_crash () =
  print_endline (Obj.magic 0 : string);
  print_endline "oops"

let rec crash_here1 = function
  | 0 -> really_crash (); 0
  | n -> crash_here2 (n - 1) + 1
and crash_here2 = function
  | 0 -> (try really_crash (); 0 with _ -> 0)
  | n -> crash_here1 (n - 1) + 1

let () =
  let n = crash_here1 5 in
  exit n

On x86 - original ocaml 3.12.1 :

$ /opt/ocaml-3.12.1/bin/ocamlopt.opt -g -inline 0 -S test.ml -o test
$ gdb -batch -ex 'set pagination 0' -ex 'set interactive-mode off' -ex 'r' -ex 'bt' -ex 'q' --args ./test

Program received signal SIGSEGV, Segmentation fault.
0x0804a370 in camlPervasives__output_string_1191 ()
#0 0x0804a370 in camlPervasives__output_string_1191 ()
#1 0x0804a76c in camlPervasives__print_endline_1274 ()
#2 0x08049a3a in camlTest__really_crash_1030 ()
0000003 0x08049a96 in camlTest__crash_here2_1032 ()
0000004 0xbffff1c8 in ?? ()
0000005 0x0804aebc in main ()

After the patch :

$ /opt/ocaml-3.12.1-cfi/bin/ocamlopt.opt -g -inline 0 -S test.ml -o test
$ gdb -batch -ex 'set pagination 0' -ex 'set interactive-mode off' -ex 'r' -ex 'bt' -ex 'q' --args ./test

Program received signal SIGSEGV, Segmentation fault.
0x0804a370 in camlPervasives__output_string_1191 ()
#0 0x0804a370 in camlPervasives__output_string_1191 ()
#1 0x0804a76c in camlPervasives__print_endline_1274 ()
#2 0x08049a3a in camlTest__really_crash_1030 ()
0000003 0x08049a96 in camlTest__crash_here2_1032 ()
0000004 0x08049abd in camlTest__crash_here1_1031 ()
0000005 0x08049a5d in camlTest__crash_here2_1032 ()
0000006 0x08049abd in camlTest__crash_here1_1031 ()
0000007 0x08049a5d in camlTest__crash_here2_1032 ()
0000008 0x08049abd in camlTest__crash_here1_1031 ()
0000009 0x08049b06 in camlTest__entry ()
0000010 0x08049791 in caml_program ()
0000011 0x08057a72 in caml_start_program ()
0000012 0x00000000 in ?? ()

On amd64 situation is better (stack seems to be always fully unwinded), but frames are still not detected correctly and backtrace contains some garbage :

$ cat test.ml
let func2 x =
  if x * x mod 111 = 0 then
    raise Not_found

let func1 x y =
  for i = x to y do
    try
      func2 i
    with exn -> print_endline "exn"
  done

let () =
  func1 100 200

$ /opt/ocaml-3.12.1/bin/ocamlopt.opt -g -inline 0 -S test.ml -o test
$ gdb -batch -ex 'set interactive-mode off' -ex 'b camlTest__func2_1030' -ex 'r' -ex 'bt' -ex 'kill' -ex 'q' --args ./test
Breakpoint 1 at 0x403550

Breakpoint 1, 0x0000000000403550 in camlTest__func2_1030 ()
#0 0x0000000000403550 in camlTest__func2_1030 ()
#1 0x00000000004035f2 in camlTest__func1_1032 ()
#2 0x00007fffffffe570 in ?? ()
0000003 0x00000000004035d7 in camlTest__func1_1032 ()
0000004 0x00000000000000c9 in ?? ()
0000005 0x0000000000000191 in ?? ()
0000006 0x0000000000411b75 in caml_start_program ()
0000007 0x000000000040365a in camlTest__entry ()
0000008 0x00000000000003e8 in ?? ()
0000009 0x0000000000403219 in caml_program ()
0000010 0x0000000000029011 in ?? ()
0000011 0x0000000000411b3e in caml_start_program ()
0000012 0x0000000000000000 in ?? ()

After the patch :
$ /opt/ocaml-3.12.1-cfi/bin/ocamlopt.opt -g -inline 0 -S test.ml -o test
$ gdb -batch -ex 'set interactive-mode off' -ex 'b camlTest__func2_1030' -ex 'r' -ex 'bt' -ex 'kill' -ex 'q' --args ./test
Breakpoint 1 at 0x403550

Breakpoint 1, 0x0000000000403550 in camlTest__func2_1030 ()
#0 0x0000000000403550 in camlTest__func2_1030 ()
#1 0x00000000004035f2 in camlTest__func1_1032 ()
#2 0x000000000040365a in camlTest__entry ()
0000003 0x0000000000403219 in caml_program ()
0000004 0x0000000000411b3e in caml_start_program ()
0000005 0x0000000000000000 in ?? ()
Additional InformationBTW, looking at asmcomp/i386/emit.mlp I am a bit puzzled : line 650, in branch Lop(Iintoffloat) : stack is growing, but stack_offset is decremented - is this correct? (I couldn't trigger storing the result to stack so maybe it doesn't matter in practice).
TagsNo tags attached.
Attached Filespatch file icon ocaml-3.12.1-cfi.patch [^] (8,492 bytes) 2011-07-10 13:01 [Show Content]
patch file icon ocaml-3.12.1-cfi2.patch [^] (19,528 bytes) 2011-07-13 19:03 [Show Content]
patch file icon ocaml-3.11.2-cfi.patch [^] (19,603 bytes) 2011-07-13 19:03 [Show Content]
patch file icon ocaml-3.11-cfi.patch [^] (19,053 bytes) 2011-08-26 09:36 [Show Content]
patch file icon ocaml-3.12-cfi.patch [^] (18,978 bytes) 2011-08-26 09:36 [Show Content]

- Relationships
related to 0005334closed ocamlopt generates stack invalid for backtrace() 

-  Notes
(0006044)
ygrek (reporter)
2011-07-13 19:03

Patch updated :
* configure test whether assembler accepts CFI directives
* annotate important runtime functions (now it is possible to see where caml_call_gc comes from)
* correct CFA for exception handlers
(0006045)
ygrek (reporter)
2011-07-13 19:04

Same patch for 3.11.2 (for testing - easy to apply on top of debian package)
(0006105)
ygrek (reporter)
2011-08-26 09:38

Patches updated:
* caml_c_call annotation was wrong, reverted
(0006199)
ygrek (reporter)
2011-11-09 22:48

Documentation for CFI directives : http://sourceware.org/binutils/docs/as/CFI-directives.html [^]
Useful example at http://www.logix.cz/michal/devel/gas-cfi/ [^]
The patch is being used for quite some time already and seems to work pretty well. Note that implementation depends on the way ocamlopt emits code, so it shortcuts some calculations (e.g. for exceptions).
Probably an important missing piece is ARM support but I do not know ARM assembly at all.
(0006321)
tgazagna (reporter)
2011-12-16 11:10

I've tested the patch as well and it works pretty well. An other missing piece is OSX support, but as on this architecture, the shipped version of as is very old (1.*), it doesn't support CFI directives. I guess generating directly .eh_sections and .debug_section is too much a pain ...
(0006326)
thelema (reporter)
2011-12-16 16:27

I've been using this final patch on a couple systems and it greatly increases the information available to me from stack traces. It makes the technique of poor man's profiling (http://poormansprofiler.org/ [^]) usable, instead of looking at just a few functions on the stack.
(0006955)
ygrek (reporter)
2012-02-22 11:52

see PR#5487

- Issue History
Date Modified Username Field Change
2011-07-10 13:01 ygrek New Issue
2011-07-10 13:01 ygrek File Added: ocaml-3.12.1-cfi.patch
2011-07-13 19:03 ygrek File Added: ocaml-3.12.1-cfi2.patch
2011-07-13 19:03 ygrek Note Added: 0006044
2011-07-13 19:03 ygrek File Added: ocaml-3.11.2-cfi.patch
2011-07-13 19:04 ygrek Note Added: 0006045
2011-08-26 09:36 ygrek File Added: ocaml-3.11-cfi.patch
2011-08-26 09:36 ygrek File Added: ocaml-3.12-cfi.patch
2011-08-26 09:38 ygrek Note Added: 0006105
2011-10-03 14:35 xleroy Relationship added related to 0005334
2011-11-09 22:48 ygrek Note Added: 0006199
2011-11-21 12:56 shinwell Status new => assigned
2011-11-21 12:56 shinwell Assigned To => shinwell
2011-12-16 11:10 tgazagna Note Added: 0006321
2011-12-16 16:27 thelema Note Added: 0006326
2012-02-22 11:52 ygrek Note Added: 0006955
2012-02-24 11:14 xleroy Status assigned => resolved
2012-02-24 11:14 xleroy Resolution open => fixed
2012-02-24 11:14 xleroy Fixed in Version => 3.13.0+dev
2013-08-31 12:48 xleroy Status resolved => closed


Copyright © 2000 - 2011 MantisBT Group
Powered by Mantis Bugtracker