Nmap Development mailing list archives
Re: [SoC] NSE pretty debugging methods
From: "Duilio Protti" <dprotti () fceia unr edu ar>
Date: Sun, 25 Mar 2007 13:11:01 -0300 (ART)
Hi, I have and idea for a pretty printer for NSE which in fact is more general than is needed to print lua_State structures, but of course it could be used to implement that in particular (probably the proposed general pretty printer should go in libnmap) The idea surrounds from PP module used in ML programs. The signature of this module is very small (you can find an API description at http://www.dina.dk/~sestoft/mosmllib/PP.html): (* PP -- pretty-printing -- from the SML/NJ library *) type ppconsumer = { consumer : string -> unit, linewidth : int, flush : unit -> unit } datatype break_style = CONSISTENT | INCONSISTENT val mk_ppstream : ppconsumer -> ppstream val dest_ppstream : ppstream -> ppconsumer val add_break : ppstream -> int * int -> unit val add_newline : ppstream -> unit val add_string : ppstream -> string -> unit val begin_block : ppstream -> break_style -> int -> unit val end_block : ppstream -> unit val clear_ppstream : ppstream -> unit val flush_ppstream : ppstream -> unit val with_pp : ppconsumer -> (ppstream -> unit) -> unit val pp_to_string : int -> (ppstream -> 'a -> unit) -> 'a -> string Aside from the specific details of what that CONSISTENT means and why you would like something like mk_ppstream, the key point is: the programmer groups related things together within blocks. Inside a block, it produce output without worrying about the context where it is. That is, programmers doesn't make formatting, they just group things together. Pretty printer takes care of doing formatting. Programmers doesn't even know where they are sending output, they just put things in a stream (a ppstream). Later they can control things as to where the output stream will be redirected and other details. To understand how it works, suppose we want to show something like a network with a list of host, and each host with a list of ports where there could be some interesting things to say. The output is something like: Net 192.168.0.0 Host 192.168.0.1 T80: some observation, probably very long U139: T10000: Host 192.168.0.2 T22: T25: some other observation Using PP module in ML this can be done as: type octet = int type IPAddress = octet * octet * octet * octet (* This is not the better datatype possible but hey! It's an example :-) *) datatype example = Net of IPAddress * example list | Host of IPAddress * (port * string list) list and port = TCP of int | UDP of int (* Let's make the pretty printer. 'pps' is the PP.ppstream *) fun prettyPrint pps example = let open PP fun ppExample (Net (ip,exs)) = (add_string pps "Net "; ppIP ip; add_break pps (0, 2); begin_block pps CONSISTENT 0; List.map ppExample exs; end_block pps) | ppExample (Host (ip,ports)) = (add_string pps "Host "; ppIP ip; add_break pps (0, 2); begin_block pps CONSISTENT 0; ppPorts ports; end_block pps; add_newline pps) and ppPorts ((port, msgs)::ports) = (ppPort port; add_string pps ": "; begin_block pps CONSISTENT 0; List.map ppPortMsg msgs; end_block pps; if ports <> [] then add_newline pps else (); ppPorts ports) | ppPorts [] = () and ppPort (TCP n) = add_string pps ("T" ^ (Int.toString n)) | ppPort (UDP n) = add_string pps ("U" ^ (Int.toString n)) and ppPortMsg s = (add_string pps s; add_newline pps) and ppIP (a,b,c,d) = add_string pps (Int.toString a ^ "." ^ Int.toString b ^ "." ^ Int.toString c ^ "." ^ Int.toString d) in begin_block pps INCONSISTENT 0; ppExample example; end_block pps end val msg1 = "this is a message" val msg2 = "this is another message" val sample1 = Net ((192,168,0,0), [Host ((192,168,0,1), [(TCP 80,[msg1,msg2]), (UDP 139,[]), (TCP 10000,[])]), Host ((192,168,0,2), [(TCP 22,[]), (TCP 25,[])])]) (* '15' is the lineWidth. If nesting groups try to indent deeper than that, the library will take care of make a clever reordering of the output in order to show things nicely *) val output1 = PP.pp_to_string 15 prettyPrint sample1 val _ = print (output1 ^ "\n") The output for this program is: Net 192.168.0.0 Host 192.168.0.1 T80: this is a message this is another message U139: T10000: Host 192.168.0.2 T22: T25: The good news is that we never produce the required tabs and spaces directly, but rather we just mark the logical structure of the stream to be printed, and the library makes all that job for us. The PP module of ML is just an example, but the important thing is that this philosophy for pretty printing presents a good separation of concerns, and while it can be used to pretty print debugging objects, it's not restricted to that. Finally, as you can imagine, it can be implemented completely in Lua, but probably would be more useful if it's offered to the entire Nmap infrastructure through C++ methods in the planned libnmap. What do you think, guys? Cheers, Duilio Protti. http://www.fceia.unr.edu.ar/~dprotti/ _______________________________________________ Sent through the nmap-dev mailing list http://cgi.insecure.org/mailman/listinfo/nmap-dev Archived at http://SecLists.Org
Current thread:
- [SoC] NSE pretty debugging methods Duilio Protti (Mar 24)
- Re: [SoC] NSE pretty debugging methods Duilio Protti (Mar 25)