[PATCH libnbd 0/3] generator: Reset line directive after included code in lib/states.c
This restores the #line directives (probably?) The output looks right, but I didn't test it beyond opening it in the editor. Do #line directives have a way to indicate "current file"? Rich.
Move the type [location] and the values [noloc], [string_of_location] and [line_directive_of_location] to [Utils]. Straightforward code motion, no change in functionality. --- generator/state_machine.ml | 12 +++--------- generator/state_machine.mli | 7 +------ generator/utils.ml | 7 +++++++ generator/utils.mli | 6 ++++++ 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/generator/state_machine.ml b/generator/state_machine.ml index d3edef4c9..3bc77f242 100644 --- a/generator/state_machine.ml +++ b/generator/state_machine.ml @@ -48,9 +48,6 @@ let string_of_external_event = function | CmdConnectSocket -> "CmdConnectSocket" | CmdIssue -> "CmdIssue" -type location = string * int -let noloc = ("", 0) - type state = { name : string; comment : string; @@ -61,7 +58,7 @@ and parsed_state = { prefix : string list; display_name : string; state_enum : string; - loc : location; + loc : Utils.location; code : string; internal_transitions : state list; events : (external_event * state) list; @@ -69,7 +66,8 @@ and parsed_state = { let default_state = { name = ""; comment = ""; external_events = []; parsed = { prefix = []; display_name = ""; - state_enum = ""; loc = noloc; code = ""; + state_enum = ""; loc = Utils.noloc; + code = ""; internal_transitions = []; events = [] } } type state_machine = state_group list @@ -878,7 +876,3 @@ and structured_reply_state_machine = [ external_events = []; }; ] - -let string_of_location (file, lineno) = sprintf "%s:%d" file lineno -let line_directive_of_location (file, lineno) = - sprintf "#line %d \"%s\"" lineno file diff --git a/generator/state_machine.mli b/generator/state_machine.mli index 4e387e3ea..020225f84 100644 --- a/generator/state_machine.mli +++ b/generator/state_machine.mli @@ -80,11 +80,6 @@ type external_event = val all_external_events : external_event list val string_of_external_event : external_event -> string -type location = string * int (** source location: file, line number *) -val noloc : location -val string_of_location : location -> string -val line_directive_of_location : location -> string - type state = { (** The state name (without prefix). If this has the special name "START" then it is the start state of the current group. Each @@ -117,7 +112,7 @@ and parsed_state = { state_enum : string; (** The C code implementing this state. *) - loc : location; + loc : Utils.location; code : string; (** Internal transitions, parsed out of the C code. *) diff --git a/generator/utils.ml b/generator/utils.ml index c326c0364..b8f394ce2 100644 --- a/generator/utils.ml +++ b/generator/utils.ml @@ -20,6 +20,9 @@ open Printf open Unix +type location = string * int +let noloc = ("", 0) + let failwithf fs = ksprintf failwith fs let rec filter_map f = function @@ -190,6 +193,10 @@ let pr_wrap ?(maxcol = 76) c code = *) pr "%s" (String.concat "\n" rest) +let string_of_location (file, lineno) = sprintf "%s:%d" file lineno +let line_directive_of_location (file, lineno) = + sprintf "#line %d \"%s\"" lineno file + type comment_style = | CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle | PODCommentStyle diff --git a/generator/utils.mli b/generator/utils.mli index b559baf76..c6ed61ce0 100644 --- a/generator/utils.mli +++ b/generator/utils.mli @@ -29,6 +29,8 @@ type comment_style = type chan = NoOutput | OutChannel of out_channel | Buffer of Buffer.t +type location = string * int (** source location: file, line number *) + val failwithf : ('a, unit, string, 'b) format4 -> 'a val filter_map : ('a -> 'b option) -> 'a list -> 'b list @@ -51,6 +53,10 @@ val output_to : string -> (unit -> 'a) -> unit val pr : ('a, unit, string, unit) format4 -> 'a val pr_wrap : ?maxcol:int -> char -> (unit -> 'a) -> unit +val noloc : location +val string_of_location : location -> string +val line_directive_of_location : location -> string + type cache_key = string type cache_value = string list val pod2text : cache_key -> cache_value -- 2.32.0
This keeps track of the current line number in the output file internally (counting from 1). It is not used for any purpose in this commit. --- generator/utils.ml | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/generator/utils.ml b/generator/utils.ml index b8f394ce2..48669f9b7 100644 --- a/generator/utils.ml +++ b/generator/utils.ml @@ -124,28 +124,25 @@ let cspan str reject = in loop 0 -(* Last output column. *) -let col = ref 0 +(* Current output line and column. *) +let lineno = ref 1 and col = ref 0 type chan = NoOutput | OutChannel of out_channel | Buffer of Buffer.t let chan = ref NoOutput let pr fs = ksprintf ( fun str -> - (* Maintain the current output column. We can simply do this - * by counting backwards from the end of the string until we - * reach a \n (or the beginning). The number we count is - * the new column. This only works for 7 bit ASCII but - * that's enough for what we need this for. + (* Maintain the current output row & column. This only + * works for 7 bit ASCII but that's enough for what we need + * this for. *) - let rec loop i acc = - if i >= 0 then ( - if String.unsafe_get str i = '\n' then acc - else loop (i-1) (acc+1) - ) - else !col + acc - in - col := loop (String.length str - 1) 0; + for i = 0 to String.length str - 1 do + if String.unsafe_get str i = '\n' then ( + col := 0; + incr lineno + ) else + incr col + done; match !chan with | NoOutput -> failwithf "use ‘output_to’ to set output" | OutChannel chan -> output_string chan str @@ -250,6 +247,7 @@ let files_equal n1 n2 = | i -> failwithf "%s: failed with error code %d" cmd i let output_to filename k = + lineno := 1; col := 0; let filename_new = filename ^ ".new" in let c = open_out filename_new in chan := OutChannel c; -- 2.32.0
--- TODO | 6 ------ generator/state_machine_generator.ml | 2 ++ generator/utils.ml | 2 ++ generator/utils.mli | 1 + 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/TODO b/TODO index 3861edc40..39642bc15 100644 --- a/TODO +++ b/TODO @@ -5,12 +5,6 @@ Bindings in other languages. - Latest attempt at adding Rust: https://www.redhat.com/archives/libguestfs/2019-August/msg00416.html -Additional #line directives in generated lib/states.c that track -position of output file when no longer copying lines from -generator/states-*.c. Probably requires moving type location, noloc, -and line_directive_of_location to utils.ml, and teaching pr to track -lines as well as columns. - Example code integrating with ppoll, pollfd, APR pollset (and others?). NBD resize extension. diff --git a/generator/state_machine_generator.ml b/generator/state_machine_generator.ml index 4e4751b76..2f4837f85 100644 --- a/generator/state_machine_generator.ml +++ b/generator/state_machine_generator.ml @@ -360,6 +360,8 @@ let generate_lib_states_c () = pr " return 0;\n"; pr "}\n"; pr "\n"; + let output_loc = "lib/states.c", output_lineno () in + pr "%s\n" (line_directive_of_location output_loc); pr "int\n"; pr "nbd_internal_enter_%s (struct nbd_handle *h, bool *blocked)\n" state_enum; diff --git a/generator/utils.ml b/generator/utils.ml index 48669f9b7..499e8f8ec 100644 --- a/generator/utils.ml +++ b/generator/utils.ml @@ -190,6 +190,8 @@ let pr_wrap ?(maxcol = 76) c code = *) pr "%s" (String.concat "\n" rest) +let output_lineno () = !lineno + let string_of_location (file, lineno) = sprintf "%s:%d" file lineno let line_directive_of_location (file, lineno) = sprintf "#line %d \"%s\"" lineno file diff --git a/generator/utils.mli b/generator/utils.mli index c6ed61ce0..21afe5529 100644 --- a/generator/utils.mli +++ b/generator/utils.mli @@ -52,6 +52,7 @@ val generate_header : ?extra_sources:string list -> comment_style -> unit val output_to : string -> (unit -> 'a) -> unit val pr : ('a, unit, string, unit) format4 -> 'a val pr_wrap : ?maxcol:int -> char -> (unit -> 'a) -> unit +val output_lineno : unit -> int val noloc : location val string_of_location : location -> string -- 2.32.0
On Fri, Dec 03, 2021 at 07:02:07PM +0000, Richard W.M. Jones wrote:
This restores the #line directives (probably?) The output looks right, but I didn't test it beyond opening it in the editor. Do #line directives have a way to indicate "current file"?
What I mean is that if you have: lib/states.c ---------------------------------------- #line 10 "generator/states.c" ... #line 20 -------------------- does the second #line refer to generator/states.c or lib/states.c? Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into KVM guests. http://libguestfs.org/virt-v2v
On Fri, Dec 03, 2021 at 07:11:46PM +0000, Richard W.M. Jones wrote:
On Fri, Dec 03, 2021 at 07:02:07PM +0000, Richard W.M. Jones wrote:
This restores the #line directives (probably?) The output looks right, but I didn't test it beyond opening it in the editor. Do #line directives have a way to indicate "current file"?
What I mean is that if you have:
lib/states.c ---------------------------------------- #line 10 "generator/states.c" ... #line 20 --------------------
does the second #line refer to generator/states.c or lib/states.c?
Alas, generator/states.c. Here's how I tested. In particular, note that you MUST use an off-by-one #line directive for the current file (the directive #line 10 must appear on line 9, for gdb to display the code at line 10 on the next step of the program). $ cat foo.c #include <stdio.h> int main(void) { int i = 1; #line 1 "bar.c" i++; // real line 7 i++; // real line 8 #line 10 i++; // real line 10 i++; // real line 11 #line 13 "foo.c" i++; // real line 13 printf("%d\n", i); return 0; } $ cat bar.c i--; // fake line 1 i--; // fake line 2 i--; // fake line 3 i--; // fake line 4 i--; // fake line 5 i--; // fake line 6 i--; // fake line 7 i--; // fake line 8 i--; // fake line 9 i--; // fake line 10 i--; // fake line 11 i--; // fake line 12 i--; // fake line 13 i--; // fake line 14 i--; // fake line 15 $ gcc -g -o foo -Wall foo.c $ gdb ./foo GNU gdb (GDB) Fedora 11.1-5.fc35 ... (gdb) b main Breakpoint 1 at 0x40112e: file foo.c, line 5. (gdb) r Starting program: /home/eblake/libnbd/foo [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". Breakpoint 1, main () at foo.c:5 5 int i = 1; (gdb) n 1 i--; // fake line 1 (gdb) 2 i--; // fake line 2 (gdb) 10 i--; // fake line 10 (gdb) 11 i--; // fake line 11 (gdb) 13 i++; // real line 13 (gdb) 14 printf("%d\n", i); (gdb) 6 15 return 0; (gdb) c Continuing. [Inferior 1 (process 3800760) exited normally] (gdb) q -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
On Fri, Dec 03, 2021 at 01:36:19PM -0600, Eric Blake wrote:
On Fri, Dec 03, 2021 at 07:11:46PM +0000, Richard W.M. Jones wrote:
On Fri, Dec 03, 2021 at 07:02:07PM +0000, Richard W.M. Jones wrote:
This restores the #line directives (probably?) The output looks right, but I didn't test it beyond opening it in the editor. Do #line directives have a way to indicate "current file"?
What I mean is that if you have:
lib/states.c ---------------------------------------- #line 10 "generator/states.c" ... #line 20 --------------------
does the second #line refer to generator/states.c or lib/states.c?
Alas, generator/states.c. Here's how I tested. In particular, note that you MUST use an off-by-one #line directive for the current file (the directive #line 10 must appear on line 9, for gdb to display the code at line 10 on the next step of the program).
In that case, patch 3 needs something like: - let output_loc = "lib/states.c", output_lineno () in + let output_loc = "lib/states.c", output_lineno () + 1 in Rich.
$ cat foo.c #include <stdio.h>
int main(void) { int i = 1; #line 1 "bar.c" i++; // real line 7 i++; // real line 8 #line 10 i++; // real line 10 i++; // real line 11 #line 13 "foo.c" i++; // real line 13 printf("%d\n", i); return 0; } $ cat bar.c i--; // fake line 1 i--; // fake line 2 i--; // fake line 3 i--; // fake line 4 i--; // fake line 5 i--; // fake line 6 i--; // fake line 7 i--; // fake line 8 i--; // fake line 9 i--; // fake line 10 i--; // fake line 11 i--; // fake line 12 i--; // fake line 13 i--; // fake line 14 i--; // fake line 15 $ gcc -g -o foo -Wall foo.c $ gdb ./foo GNU gdb (GDB) Fedora 11.1-5.fc35 ... (gdb) b main Breakpoint 1 at 0x40112e: file foo.c, line 5. (gdb) r Starting program: /home/eblake/libnbd/foo [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1".
Breakpoint 1, main () at foo.c:5 5 int i = 1; (gdb) n 1 i--; // fake line 1 (gdb) 2 i--; // fake line 2 (gdb) 10 i--; // fake line 10 (gdb) 11 i--; // fake line 11 (gdb) 13 i++; // real line 13 (gdb) 14 printf("%d\n", i); (gdb) 6 15 return 0; (gdb) c Continuing. [Inferior 1 (process 3800760) exited normally] (gdb) q
-- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://people.redhat.com/~rjones/virt-top
On Fri, Dec 03, 2021 at 07:38:49PM +0000, Richard W.M. Jones wrote:
Alas, generator/states.c. Here's how I tested. In particular, note that you MUST use an off-by-one #line directive for the current file (the directive #line 10 must appear on line 9, for gdb to display the code at line 10 on the next step of the program).
In that case, patch 3 needs something like:
- let output_loc = "lib/states.c", output_lineno () in + let output_loc = "lib/states.c", output_lineno () + 1 in
Yep, with that change, my gdb session single-stepping through the state machine lines up with the code being executed. ACK series, and thanks for tackling this! -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
On Fri, Dec 03, 2021 at 01:56:02PM -0600, Eric Blake wrote:
On Fri, Dec 03, 2021 at 07:38:49PM +0000, Richard W.M. Jones wrote:
Alas, generator/states.c. Here's how I tested. In particular, note that you MUST use an off-by-one #line directive for the current file (the directive #line 10 must appear on line 9, for gdb to display the code at line 10 on the next step of the program).
In that case, patch 3 needs something like:
- let output_loc = "lib/states.c", output_lineno () in + let output_loc = "lib/states.c", output_lineno () + 1 in
Yep, with that change, my gdb session single-stepping through the state machine lines up with the code being executed. ACK series, and thanks for tackling this!
I pushed this as commits 38ce5836aa and f78ef5647d. The second commit contains patches 2 & 3 squashed together (plus extra fix) because that seemed to make more sense. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 100 libraries supported. http://fedoraproject.org/wiki/MinGW
participants (2)
-
Eric Blake -
Richard W.M. Jones