user: 请从给定的汇编指令推导出C源代码:

```asm
<crumb_canonize_path>:
  endbr64
  push   %r15
  push   %r14
  push   %r13
  push   %r12
  push   %rbp
  push   %rbx
  sub    $0x228,%rsp
  mov    %rdi,%rbx
  mov    %rsi,%r13
  mov    %edx,%r12d
  mov    %fs:0x28,%rax
  mov    %rax,0x218(%rsp)
  xor    %eax,%eax
  call   <strlen@plt>
  test   %eax,%eax
  jne    L102
  movb   $0x0,0x0(%r13)
L117:
  mov    0x218(%rsp),%rax
  sub    %fs:0x28,%rax
  jne    L3
  add    $0x228,%rsp
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  pop    %r15
  ret
L102:
  mov    %eax,%ebp
  lea    0x10(%rsp),%rdi
  mov    $0x200,%esi
  call   <getcwd@plt>
  mov    %rax,%r14
  mov    $0x2f,%esi
  mov    %rbx,%rdi
  call   <strrchr@plt>
  mov    %rax,%rdx
  movslq %ebp,%rbp
  lea    -0x1(%rbx,%rbp,1),%rax
  cmp    %rax,%rdx
  sete   %al
  movzbl %al,%eax
  mov    %eax,0xc(%rsp)
  cmpb   $0x2f,(%rbx)
  jne    L38
  movb   $0x2f,0x0(%r13)
  movb   $0x0,0x1(%r13)
  lea    0x1(%r13),%r12
L65:
  mov    $0x0,%r14d
  lea    D15(%rip),%r15
  mov    $0x0,%eax
  cmpb   $0x0,(%rbx)
  jne    L136
L180:
  or     0xc(%rsp),%eax
  jne    L117
  cmp    %r12,%r13
  jae    L117
  cmpb   $0x2f,-0x1(%r12)
  jne    L117
  movb   $0x0,-0x1(%r12)
  jmp    L117
L38:
  mov    %r14,%rcx
  lea    D4(%rip),%rdx
  mov    %r12d,%esi
  mov    %r13,%rdi
  call   <snprintf@plt>
  mov    %r13,%rdi
  call   <strlen@plt>
  movslq %eax,%r12
  add    %r13,%r12
  jmp    L65
L1:
  mov    %r12,%rbp
  jmp    L129
L107:
  lea    -0x1(%rbp),%r12
  movb   $0x0,-0x1(%rbp)
  mov    $0x1,%eax
  jmp    L7
L124:
  movb   $0x0,-0x3(%rbp)
  mov    $0x2f,%esi
  mov    %r13,%rdi
  call   <strrchr@plt>
  test   %rax,%rax
  je     L86
  lea    0x1(%rax),%r12
  movb   $0x0,0x1(%rax)
  mov    $0x1,%eax
  jmp    L7
L86:
  movb   $0x0,0x0(%r13)
  mov    %r13,%r12
  mov    $0x1,%eax
  jmp    L7
L11:
  mov    %rbp,%r12
  mov    %r14d,%eax
L7:
  cmpb   $0x0,(%rbx)
  je     L180
L136:
  mov    $0x2f,%esi
  mov    %rbx,%rdi
  call   <strchrnul@plt>
  cmp    %rbx,%rax
  jbe    L1
  mov    %rax,%rbp
  sub    %rbx,%rbp
  mov    $0x0,%edx
L177:
  movzbl (%rbx,%rdx,1),%ecx
  mov    %cl,(%r12,%rdx,1)
  add    $0x1,%rdx
  cmp    %rdx,%rbp
  jne    L177
  add    %r12,%rbp
  mov    %rax,%rbx
L129:
  cmpb   $0x2f,(%rbx)
  sete   %al
  movzbl %al,%eax
  add    %rax,%rbx
  movb   $0x0,0x0(%rbp)
  cmpb   $0x0,(%r12)
  je     L11
  mov    %r15,%rsi
  mov    %r12,%rdi
  call   <strcmp@plt>
  test   %eax,%eax
  je     L107
  lea    D17(%rip),%rsi
  mov    %r12,%rdi
  call   <strcmp@plt>
  test   %eax,%eax
  je     L124
  movb   $0x2f,0x0(%rbp)
  lea    0x1(%rbp),%r12
  movb   $0x0,0x1(%rbp)
  mov    %r14d,%eax
  jmp    L7
L3:
  call   <__stack_chk_fail@plt>
```

tool_calls: name: extract_symbolic_data
arguments: data_tag: D15
type_infered: string
name: extract_symbolic_data
arguments: data_tag: D4
type_infered: string
name: extract_symbolic_data
arguments: data_tag: D17
type_infered: string

tool: D15: .

tool: D4: %s/

tool: D17: ..

assistant: ```c
void crumb_canonize_path(const char *filename, char *ostr, int ostr_max) {
  char bcwd[0x200], *cwd;
  const char *b, *scan = filename;
  char *o, *x, *p;
  int dont_remove_slash = 0, last_is_dotted = 0;
  int lf = strlen(filename);
  if (lf == 0) {
    *ostr = '\0';
    return;
  }
  cwd = getcwd(bcwd, sizeof(bcwd));
  if (strrchr(filename, '/') == filename + lf - 1) {
    dont_remove_slash = 1;
  }
  if (filename[0] != '/') {
    snprintf(ostr, ostr_max, "%s/", cwd);
    o = ostr + strlen(ostr);
  } else {
    o = ostr;
    o[0] = '/';
    o[1] = '\0';
    o++;
  }
  while (*scan != '\0') {
    p = strchrnul(scan, '/');
    b = o;
    while (scan < p) {
      *o = *scan;
      o++;
      scan++;
    }
    if (*scan == '/')
      scan++;
    o[0] = '\0';
    last_is_dotted = 0;
    if (!strcmp(b, "")) {
      continue;
    }
    if (!strcmp(b, ".")) {
      o -= 1;
      o[0] = '\0';
      last_is_dotted = 1;
      continue;
    }
    if (!strcmp(b, "..")) {
      o -= 3;
      o[0] = '\0';
      x = strrchr(ostr, '/');
      if (x) {
        o = x + 1;
        *o = '\0';
      } else {
        o = ostr;
        *o = '\0';
      }
      last_is_dotted = 1;
      continue;
    }
    o[0] = '/';
    o++;
    o[0] = '\0';
  }
  if (!dont_remove_slash && !last_is_dotted) {
    if (o > ostr && o[-1] == '/')
      o[-1] = '\0';
  }
}
```