Bcc: string functions

Created on 15 Sep 2016  路  4Comments  路  Source: iovisor/bcc

This is on BPF tasks #574 as string factory (stringmap). Can we propose a minimal set of functions we'd like, to begin with? Here's my list:

  • strstr() or strncmp() (or both)
  • strlcat() and strlen(), or a basic snprintf()

Examples of current workarounds: strcmp():

strlcat():

This emits arguments one by one. This is tricky, since we need to walk argv[] (currently using an unrolled loop). I was thinking strlcat() would let us build a concatenated args string, but it might need strlen() at some point. A basic snprintf() sounds much better, but .. gah this is awful.

How about a helper just for the argv[] case? :) Ie, take an argv[] argument and return a truncated string of the arguments. bpf_strarray_to_str().

Then, in lieu of another use case, my list is just:

  • strstr() or strncmp() (or both)
  • bpf_strarray_to_str()

@4ast may have another thread of discussion about this. I'm posting this here as it was suggested in IRC.

Most helpful comment

Fun workaround, but it would still be nice to see this as a builtin.

Few of my coworkers hit this: @shartse @don-brady

All 4 comments

Thanks for filing this issue. /cc @alban @asymmetric @alepuccetti @iaguis @2opremio

I'd really like strcpy, which is very needed in argdist (see #607) so we don't do aggregations based on extraneous characters (which almost always leads to wrong results when aggregating on strings without specifying the exact string size).

from @goldshtn on #759:

So, I ran a little test. It looks like we can definitely use loops that implement strcmp manually if the string is known at compile-time. This opens up a bunch of use cases for scripts where we don't really need to compare two run-time strings, but rather compare one run-time string to one compile-time string (like your example above).

Here's a function that compares a run-time string to "true". It can be used from a bcc program.

static inline bool equal_to_true(char *str) {
  char comparand[4];
  bpf_probe_read(&comparand, sizeof(comparand), str);
  char compare[] = "true";
  for (int i = 0; i < 4; ++i)
    if (compare[i] != comparand[i])
      return false;
  return true;
}

This can be generalized into a macro:

 #include <linux/ptrace.h>                                                       

 #define DECLARE_EQUAL_TO(s) static inline bool equal_to_##s(char *str) { \      
     char comparand[sizeof(#s)]; \                                               
     bpf_probe_read(&comparand, sizeof(comparand), str); \                       
     char compare[] = #s; \                                                      
     for (int i = 0; i < sizeof(comparand); ++i) \                               
         if (compare[i] != comparand[i]) \                                       
             return false; \                                                     
     return true; \                                                              
 } \                                                                             

 #define IS_EQUAL_TO(str, s) equal_to_##s(str)                                   

 DECLARE_EQUAL_TO(true)                                                          

 int test_strings(struct pt_regs *ctx, char *str) {                              
     bpf_trace_printk("String printed: %s, equal to 'true': %d\\n",              
         str, IS_EQUAL_TO(str, true));                                           
     return 0;                                                                   
 }                               

It's not elegant, but seems to be working. I think it can be incorporated into trace and argdist so we can compare strings. Thoughts? :)

Fun workaround, but it would still be nice to see this as a builtin.

Few of my coworkers hit this: @shartse @don-brady

Was this page helpful?
0 / 5 - 0 ratings